OSDN Git Service

Merge "Fix null deref crash" into nyc-mr1-dev
authorJohn Reck <jreck@google.com>
Mon, 1 Aug 2016 21:54:13 +0000 (21:54 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Mon, 1 Aug 2016 21:54:14 +0000 (21:54 +0000)
49 files changed:
core/java/android/app/ITransientNotification.aidl
core/java/android/content/pm/LauncherApps.java
core/java/android/view/SurfaceView.java
core/java/android/view/WindowManager.java
core/java/android/widget/RatingBar.java
core/java/android/widget/Toast.java
core/res/res/color/watch_switch_thumb_color_material.xml
docs/html-intl/intl/es/training/articles/direct-boot.jd
docs/html-intl/intl/es/training/articles/scoped-directory-access.jd
docs/html-intl/intl/es/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/es/training/tv/tif/content-recording.jd
docs/html-intl/intl/in/training/articles/direct-boot.jd
docs/html-intl/intl/in/training/articles/scoped-directory-access.jd
docs/html-intl/intl/in/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/in/training/tv/tif/content-recording.jd
docs/html-intl/intl/ja/training/articles/direct-boot.jd
docs/html-intl/intl/ja/training/articles/scoped-directory-access.jd
docs/html-intl/intl/ja/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/ja/training/tv/tif/content-recording.jd
docs/html-intl/intl/ko/training/articles/direct-boot.jd
docs/html-intl/intl/ko/training/articles/scoped-directory-access.jd
docs/html-intl/intl/ko/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/ko/training/tv/tif/content-recording.jd
docs/html-intl/intl/pt-br/training/articles/direct-boot.jd
docs/html-intl/intl/pt-br/training/articles/scoped-directory-access.jd
docs/html-intl/intl/pt-br/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/pt-br/training/tv/tif/content-recording.jd
docs/html-intl/intl/ru/training/articles/direct-boot.jd
docs/html-intl/intl/ru/training/articles/scoped-directory-access.jd
docs/html-intl/intl/ru/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/ru/training/tv/tif/content-recording.jd
docs/html-intl/intl/vi/training/articles/direct-boot.jd
docs/html-intl/intl/vi/training/articles/scoped-directory-access.jd
docs/html-intl/intl/vi/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/vi/training/tv/tif/content-recording.jd
docs/html-intl/intl/zh-cn/training/articles/direct-boot.jd
docs/html-intl/intl/zh-cn/training/articles/scoped-directory-access.jd
docs/html-intl/intl/zh-cn/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/zh-cn/training/tv/tif/content-recording.jd
docs/html-intl/intl/zh-tw/training/articles/direct-boot.jd
docs/html-intl/intl/zh-tw/training/articles/scoped-directory-access.jd
docs/html-intl/intl/zh-tw/training/tv/playback/picture-in-picture.jd
docs/html-intl/intl/zh-tw/training/tv/tif/content-recording.jd
docs/html/about/dashboards/index.jd
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/pm/ShortcutService.java
services/core/java/com/android/server/policy/PhoneWindowManager.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/core/java/com/android/server/wm/WindowState.java

index 35b53a4..d5b3ed0 100644 (file)
@@ -19,7 +19,7 @@ package android.app;
 
 /** @hide */
 oneway interface ITransientNotification {
-    void show();
+    void show(IBinder windowToken);
     void hide();
 }
 
index 6b23da9..b9b609b 100644 (file)
@@ -492,7 +492,7 @@ public class LauncherApps {
      * If the calling launcher application contains pinned shortcuts, they will still work,
      * even though the caller no longer has the shortcut host permission.
      *
-     * @throws IllegalStateException when the user is locked.
+     * <p>Returns {@code false} when the user is locked.
      *
      * @see ShortcutManager
      */
@@ -510,12 +510,13 @@ public class LauncherApps {
      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
      * #hasShortcutHostPermission()}.
      *
+     * <p>Returns am empty list when the user is locked, or when the {@code user} user
+     * is locked or not running.
+     *
      * @param query result includes shortcuts matching this query.
      * @param user The UserHandle of the profile.
      *
      * @return the IDs of {@link ShortcutInfo}s that match the query.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @see ShortcutManager
      */
@@ -555,11 +556,12 @@ public class LauncherApps {
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
+     * <p>Call will be ignored when the user is locked, or when the {@code user} user
+     * is locked or not running.
+     *
      * @param packageName The target package name.
      * @param shortcutIds The IDs of the shortcut to be pinned.
      * @param user The UserHandle of the profile.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @see ShortcutManager
      */
@@ -628,12 +630,13 @@ public class LauncherApps {
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
+     * <p>Returns {@code null} when the user is locked, or when the user owning the shortcut
+     * is locked or not running.
+     *
      * @param density The preferred density of the icon, zero for default density. Use
      * density DPI values from {@link DisplayMetrics}.
      *
      * @return The drawable associated with the shortcut.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @see ShortcutManager
      * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
@@ -678,10 +681,11 @@ public class LauncherApps {
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
+     * <p>Returns {@code 0} when the user is locked, or when the user owning the shortcut
+     * is locked or not running.
+     *
      * @param density Optional density for the icon, or 0 to use the default density. Use
      * @return A badged icon for the shortcut.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @see ShortcutManager
      * @see #getShortcutIconDrawable(ShortcutInfo, int)
@@ -700,13 +704,15 @@ public class LauncherApps {
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
+     * <p>Throws {@link android.content.ActivityNotFoundException}
+     * when the user is locked, or when the {@code user} user
+     * is locked or not running.
+     *
      * @param packageName The target shortcut package name.
      * @param shortcutId The target shortcut ID.
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
      * @param user The UserHandle of the profile.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
@@ -724,11 +730,13 @@ public class LauncherApps {
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
+     * <p>Throws {@link android.content.ActivityNotFoundException}
+     * when the user is locked, or when the user owning the shortcut
+     * is locked or not running.
+     *
      * @param shortcut The target shortcut.
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
-     * @throws IllegalStateException when the user is locked, or when the {@code user} user
-     * is locked or not running.
      *
      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
index 4818910..b6955a8 100644 (file)
@@ -233,6 +233,7 @@ public class SurfaceView extends View {
         mSession = getWindowSession();
         mLayout.token = getWindowToken();
         mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
+        mLayout.packageName = mContext.getOpPackageName();
         mViewVisibility = getVisibility() == VISIBLE;
 
         if (!mGlobalListenersAdded) {
index fe24230..4a20619 100644 (file)
@@ -1734,14 +1734,18 @@ public interface WindowManager extends ViewManager {
         public CharSequence accessibilityTitle;
 
         /**
-         * Sets a timeout in milliseconds before which the window will be removed
+         * Sets a timeout in milliseconds before which the window will be hidden
          * by the window manager. Useful for transient notifications like toasts
          * so we don't have to rely on client cooperation to ensure the window
-         * is removed. Must be specified at window creation time.
+         * is hidden. Must be specified at window creation time. Note that apps
+         * are not prepared to handle their windows being removed without their
+         * explicit request and may try to interact with the removed window
+         * resulting in undefined behavior and crashes. Therefore, we do hide
+         * such windows to prevent them from overlaying other apps.
          *
          * @hide
          */
-        public long removeTimeoutMilliseconds = -1;
+        public long hideTimeoutMilliseconds = -1;
 
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
@@ -1877,7 +1881,7 @@ public interface WindowManager extends ViewManager {
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
-            out.writeLong(removeTimeoutMilliseconds);
+            out.writeLong(hideTimeoutMilliseconds);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1931,7 +1935,7 @@ public interface WindowManager extends ViewManager {
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            removeTimeoutMilliseconds = in.readLong();
+            hideTimeoutMilliseconds = in.readLong();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2153,7 +2157,7 @@ public interface WindowManager extends ViewManager {
             }
 
             // This can't change, it's only set at window creation time.
-            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+            hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;
 
             return changes;
         }
index 2230961..3ad05b5 100644 (file)
@@ -110,8 +110,8 @@ public class RatingBar extends AbsSeekBar {
         }
 
         // A touch inside a star fill up to that fractional area (slightly more
-        // than 1 so boundaries round up).
-        mTouchProgressOffset = 1.1f;
+        // than 0.5 so boundaries round up).
+        mTouchProgressOffset = 0.6f;
     }
 
     public RatingBar(Context context, AttributeSet attrs) {
index 7762675..eca10cb 100644 (file)
@@ -25,6 +25,8 @@ import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -326,13 +328,6 @@ public class Toast {
     }
 
     private static class TN extends ITransientNotification.Stub {
-        final Runnable mShow = new Runnable() {
-            @Override
-            public void run() {
-                handleShow();
-            }
-        };
-
         final Runnable mHide = new Runnable() {
             @Override
             public void run() {
@@ -343,7 +338,13 @@ public class Toast {
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler();
+        final Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                IBinder token = (IBinder) msg.obj;
+                handleShow(token);
+            }
+        };
 
         int mGravity;
         int mX, mY;
@@ -379,9 +380,9 @@ public class Toast {
          * schedule handleShow into the right thread
          */
         @Override
-        public void show() {
+        public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
-            mHandler.post(mShow);
+            mHandler.obtainMessage(0, windowToken).sendToTarget();
         }
 
         /**
@@ -393,7 +394,7 @@ public class Toast {
             mHandler.post(mHide);
         }
 
-        public void handleShow() {
+        public void handleShow(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -422,8 +423,9 @@ public class Toast {
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 mParams.packageName = packageName;
-                mParams.removeTimeoutMilliseconds = mDuration ==
+                mParams.hideTimeoutMilliseconds = mDuration ==
                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
+                mParams.token = windowToken;
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
index a931724..d4796a0 100644 (file)
@@ -12,6 +12,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?android:colorAccent" android:state_checked="true" />
-    <item android:color="?android:colorButtonNormal" android:state_checked="false" />
+    <item android:color="?android:colorButtonNormal" android:state_enabled="false" />
+    <item android:color="?android:colorControlActivated" android:state_checked="true" />
+    <item android:color="?android:colorButtonNormal" />
 </selector>
\ No newline at end of file
index e1d99e9..0ce3f5b 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>En este documento</h2>
   <ol>
     <li><a href="#run">Solicitar acceso para ejecutar durante el inicio directo</a></li>
index 67f9ad6..194bfd7 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>En este documento</h2>
   <ol>
     <li><a href="#accessing">Acceder a un directorio de almacenamiento externo</a></li>
index 0aa46dc..30c9e8b 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>En este documento</h2>
 <ol>
index 855db8d..9e8a346 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>En este documento</h2>
   <ol>
     <li><a href="#supporting">Indicar la compatibilidad para la grabación</a></li>
index b06a7dd..a7e3cf3 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Dalam dokumen ini</h2>
   <ol>
     <li><a href="#run">Meminta Akses untuk Berjalan Selama Direct Boot</a></li>
index 855993f..30aed6f 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Dalam dokumen ini</h2>
   <ol>
     <li><a href="#accessing">Mengakses Direktori Penyimpanan Eksternal</a></li>
index 1cad955..41af6de 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>Dalam dokumen ini</h2>
 <ol>
index afedf8f..3389dbf 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Dalam dokumen ini</h2>
   <ol>
     <li><a href="#supporting">Menunjukkan Dukungan untuk Perekaman</a></li>
index 933e682..eaa684c 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>このドキュメントの内容</h2>
   <ol>
     <li><a href="#run">ダイレクト ブート中に実行するためのアクセスを要求する</a></li>
index 32681a0..0767689 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>このドキュメントの内容</h2>
   <ol>
     <li><a href="#accessing">外部ストレージのディレクトリへのアクセス</a></li>
index 7593670..1df16cd 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>このドキュメントの内容</h2>
 <ol>
index bf5f9a9..3c58cfd 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>このドキュメントの内容</h2>
   <ol>
     <li><a href="#supporting">録画のサポートを示す</a></li>
index 2674481..e58a4f9 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>이 문서의 내용</h2>
   <ol>
     <li><a href="#run">직접 부팅 시 실행하기 위한 액세스 요청</a></li>
index efd05f3..f2ce650 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>이 문서의 내용</h2>
   <ol>
     <li><a href="#accessing">외부 저장소 디렉터리 액세스</a></li>
index 15d85fa..96129ce 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>이 문서의 내용</h2>
 <ol>
index fa557bc..ed8b6e0 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>이 문서의 내용</h2>
   <ol>
     <li><a href="#supporting">녹화 지원 나타내기</a></li>
index 8f58841..d95f4cd 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Neste documento</h2>
   <ol>
     <li><a href="#run">Solicitar acesso para executar durante a inicialização direta</a></li>
index a4c51ab..215afd1 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Neste documento</h2>
   <ol>
     <li><a href="#accessing">Acessar um diretório de armazenamento externo</a></li>
index 14f5209..baa7d61 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>Neste documento</h2>
 <ol>
index 890e140..c6d7bb7 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Neste documento</h2>
   <ol>
     <li><a href="#supporting">Indicar suporte para gravação</a></li>
index 3392c13..98849fe 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Содержание документа</h2>
   <ol>
     <li><a href="#run">Запрос доступа для запуска в режиме Direct Boot</a></li>
index f70c92c..3e67d35 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Содержание документа</h2>
   <ol>
     <li><a href="#accessing">Доступ к каталогу во внешнем хранилище</a></li>
index f0ffd48..fc26368 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>Содержание документа</h2>
 <ol>
index 5e6ce45..19d6db3 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Содержание документа</h2>
   <ol>
     <li><a href="#supporting">Указание на поддержку записи</a></li>
index 9b2a557..c93e255 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Trong tài liệu này</h2>
   <ol>
     <li><a href="#run">Yêu cầu Truy cập để Chạy trong quá trình Khởi động Trực tiếp</a></li>
index d3b7174..a4d9779 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Trong tài liệu này</h2>
   <ol>
     <li><a href="#accessing">Truy cập một Thư mục lưu trữ bên ngoài</a></li>
index 8146a15..9156152 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>Trong tài liệu này</h2>
 <ol>
index 6dfb53e..bfd718b 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>Trong tài liệu này</h2>
   <ol>
     <li><a href="#supporting">Chỉ báo Hỗ trợ ghi lại</a></li>
index 306a7a4..20f8b57 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>本文内容</h2>
   <ol>
     <li><a href="#run">请求在直接启动时运行</a></li>
index 6473fc8..83d50b4 100644 (file)
@@ -8,8 +8,8 @@ page.tags=Android N
 
 
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>本文内容</h2>
   <ol>
     <li><a href="#accessing">访问外部存储目录</a></li>
index 782b5b8..6cfa815 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>本文内容</h2>
 <ol>
index 2dec87d..754e065 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>本文内容</h2>
   <ol>
     <li><a href="#supporting">指示支持录制</a></li>
index 7e4ea73..fdcb172 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>此文件內容</h2>
   <ol>
     <li><a href="#run">要求直接開機期間的執行權限</a></li>
index 0aa0034..b1c1a76 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>此文件內容</h2>
   <ol>
     <li><a href="#accessing">存取外部儲存空間目錄</a></li>
index b051985..e643f65 100644 (file)
@@ -4,8 +4,8 @@ page.tags=androidn
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
 
 <h2>此文件內容</h2>
 <ol>
index d857477..8b3a5ce 100644 (file)
@@ -5,8 +5,8 @@ page.image=images/cards/card-nyc_2x.jpg
 
 @jd:body
 
-<div id="qv-wrapper">
-<div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
   <h2>此文件內容</h2>
   <ol>
     <li><a href="#supporting">指出錄製支援</a></li>
index 3cbfde9..f5d23e8 100644 (file)
@@ -59,7 +59,7 @@ Platform Versions</a>.</p>
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -81,7 +81,7 @@ Screens</a>.</p>
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
 
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
@@ -101,7 +101,7 @@ support for any lower version (for example, support for version 2.0 also implies
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A47.5%2C41.9%2C10.6&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -119,21 +119,21 @@ uses.</p>
 </tr>
 <tr>
 <td>2.0</td>
-<td>47.5%</td>
+<td>46.0%</td>
 </tr>
 <tr>
 <td>3.0</td>
-<td>41.9%</td>
+<td>42.6%</td>
 </tr>
 <tr>
 <td>3.1</td>
-<td>10.6%</td>
+<td>11.4%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p>
 
 
 
@@ -147,19 +147,19 @@ var SCREEN_DATA =
       "Large": {
         "hdpi": "0.5",
         "ldpi": "0.2",
-        "mdpi": "4.4",
+        "mdpi": "4.3",
         "tvdpi": "2.1",
         "xhdpi": "0.5"
       },
       "Normal": {
-        "hdpi": "40.9",
-        "mdpi": "4.1",
+        "hdpi": "40.0",
+        "mdpi": "3.8",
         "tvdpi": "0.1",
-        "xhdpi": "26.3",
-        "xxhdpi": "15.1"
+        "xhdpi": "27.3",
+        "xxhdpi": "15.5"
       },
       "Small": {
-        "ldpi": "1.9"
+        "ldpi": "1.8"
       },
       "Xlarge": {
         "hdpi": "0.3",
@@ -167,8 +167,8 @@ var SCREEN_DATA =
         "xhdpi": "0.7"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A2.1%2C11.4%2C2.2%2C41.7%2C27.5%2C15.1&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A3.9%2C7.7%2C86.5%2C1.9&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c"
   }
 ];
 
@@ -176,7 +176,7 @@ var SCREEN_DATA =
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A0.1%2C1.9%2C1.7%2C17.8%2C30.2%2C35.1%2C13.3&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 8,
@@ -186,47 +186,47 @@ var VERSION_DATA =
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "1.9"
+        "perc": "1.7"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "1.7"
+        "perc": "1.6"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "6.4"
+        "perc": "6.0"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "8.8"
+        "perc": "8.3"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "2.6"
+        "perc": "2.4"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "30.1"
+        "perc": "29.2"
       },
       {
         "api": 21,
         "name": "Lollipop",
-        "perc": "14.3"
+        "perc": "14.1"
       },
       {
         "api": 22,
         "name": "Lollipop",
-        "perc": "20.8"
+        "perc": "21.4"
       },
       {
         "api": 23,
         "name": "Marshmallow",
-        "perc": "13.3"
+        "perc": "15.2"
       }
     ]
   }
index 8b5942c..de1d7a7 100644 (file)
@@ -58,7 +58,6 @@ import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
-import android.app.RemoteInput;
 import android.app.StatusBarManager;
 import android.app.backup.BackupManager;
 import android.app.usage.UsageEvents;
@@ -93,7 +92,6 @@ import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -122,6 +120,8 @@ import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+import android.view.WindowManager;
+import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
@@ -138,6 +138,7 @@ import com.android.server.SystemService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
+import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.notification.ManagedServices.UserProfiles;
@@ -193,7 +194,7 @@ public class NotificationManagerService extends SystemService {
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
     private static final int MESSAGE_RANKING_SORT = 1001;
 
-    static final int LONG_DELAY = 3500; // 3.5 seconds
+    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
     static final int SHORT_DELAY = 2000; // 2 seconds
 
     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
@@ -232,6 +233,7 @@ public class NotificationManagerService extends SystemService {
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private VrManagerInternal mVrManagerInternal;
+    private WindowManagerInternal mWindowManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
     private Handler mHandler;
@@ -452,13 +454,15 @@ public class NotificationManagerService extends SystemService {
         final String pkg;
         final ITransientNotification callback;
         int duration;
+        Binder token;
 
-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
-        {
+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
+                    Binder token) {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
+            this.token = token;
         }
 
         void update(int duration) {
@@ -1125,6 +1129,7 @@ public class NotificationManagerService extends SystemService {
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mVrManagerInternal = getLocalService(VrManagerInternal.class);
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -1325,10 +1330,13 @@ public class NotificationManagerService extends SystemService {
                             }
                         }
 
-                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        Binder token = new Binder();
+                        mWindowManagerInternal.addWindowToken(token,
+                                WindowManager.LayoutParams.TYPE_TOAST);
+                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveLocked(callingPid);
+                        keepProcessAliveIfNeededLocked(callingPid);
                     }
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
@@ -2987,7 +2995,7 @@ public class NotificationManagerService extends SystemService {
         while (record != null) {
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
-                record.callback.show();
+                record.callback.show(record.token);
                 scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
@@ -2998,7 +3006,7 @@ public class NotificationManagerService extends SystemService {
                 if (index >= 0) {
                     mToastQueue.remove(index);
                 }
-                keepProcessAliveLocked(record.pid);
+                keepProcessAliveIfNeededLocked(record.pid);
                 if (mToastQueue.size() > 0) {
                     record = mToastQueue.get(0);
                 } else {
@@ -3018,8 +3026,11 @@ public class NotificationManagerService extends SystemService {
             // don't worry about this, we're about to remove it from
             // the list anyway
         }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
+
+        ToastRecord lastToast = mToastQueue.remove(index);
+        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
+
+        keepProcessAliveIfNeededLocked(record.pid);
         if (mToastQueue.size() > 0) {
             // Show the next one. If the callback fails, this will remove
             // it from the list, so don't assume that the list hasn't changed
@@ -3063,7 +3074,7 @@ public class NotificationManagerService extends SystemService {
     }
 
     // lock on mToastQueue
-    void keepProcessAliveLocked(int pid)
+    void keepProcessAliveIfNeededLocked(int pid)
     {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
index 02ad7c6..d875f1e 100644 (file)
@@ -2170,9 +2170,9 @@ public class ShortcutService extends IShortcutService.Stub {
                 @Nullable ComponentName componentName,
                 int queryFlags, int userId) {
             final ArrayList<ShortcutInfo> ret = new ArrayList<>();
-
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return ret;
+            }
 
             final boolean cloneKeyFieldOnly =
                     ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
@@ -2251,8 +2251,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return false;
+            }
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
@@ -2270,8 +2271,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return null;
+            }
 
             final ShortcutPackage p = getUserShortcutsLocked(userId)
                     .getPackageShortcutsIfExists(packageName);
@@ -2294,8 +2296,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkNotNull(shortcutIds, "shortcutIds");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return;
+            }
 
             synchronized (mLock) {
                 final ShortcutLauncher launcher =
@@ -2317,8 +2320,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return null;
+            }
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
@@ -2350,8 +2354,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkNotNull(packageName, "packageName");
             Preconditions.checkNotNull(shortcutId, "shortcutId");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return 0;
+            }
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
@@ -2377,8 +2382,9 @@ public class ShortcutService extends IShortcutService.Stub {
             Preconditions.checkNotNull(packageName, "packageName");
             Preconditions.checkNotNull(shortcutId, "shortcutId");
 
-            throwIfUserLocked(userId);
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
+                return null;
+            }
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
@@ -2412,7 +2418,9 @@ public class ShortcutService extends IShortcutService.Stub {
         @Override
         public boolean hasShortcutHostPermission(int launcherUserId,
                 @NonNull String callingPackage) {
-            throwIfUserLocked(launcherUserId);
+            if (!isUserUnlocked(launcherUserId)) {
+                return false;
+            }
             return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
         }
     }
index e502764..6253963 100644 (file)
@@ -301,6 +301,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
+    /** Amount of time (in milliseconds) a toast window can be shown. */
+    public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
+
     /**
      * Lock protecting internal state.  Must not call out into window
      * manager with lock held.  (This lock will be acquired in places
@@ -2229,6 +2232,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
+
+            case TYPE_TOAST:
+                // While apps should use the dedicated toast APIs to add such windows
+                // it possible legacy apps to add the window directly. Therefore, we
+                // make windows added directly by the app behave as a toast as much
+                // as possible in terms of timeout and animation.
+                if (attrs.hideTimeoutMilliseconds < 0
+                        || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
+                    attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
+                }
+                attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
+                break;
         }
 
         if (attrs.type != TYPE_STATUS_BAR) {
index 6451c74..70a1ee6 100644 (file)
@@ -35,6 +35,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -200,6 +201,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -1867,6 +1869,7 @@ public class WindowManagerService extends IWindowManager.Stub
         boolean reportNewConfig = false;
         WindowState attachedWindow = null;
         long origId;
+        final int callingUid = Binder.getCallingUid();
         final int type = attrs.type;
 
         synchronized(mWindowMap) {
@@ -1914,6 +1917,8 @@ public class WindowManagerService extends IWindowManager.Stub
             boolean addToken = false;
             WindowToken token = mTokenMap.get(attrs.token);
             AppWindowToken atoken = null;
+            boolean addToastWindowRequiresToken = false;
+
             if (token == null) {
                 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG_WM, "Attempted to add application window with unknown token "
@@ -1950,6 +1955,15 @@ public class WindowManagerService extends IWindowManager.Stub
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+                if (type == TYPE_TOAST) {
+                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
+                            attachedWindow)) {
+                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
+                                + attrs.token + ".  Aborting.");
+                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    }
+                }
                 token = new WindowToken(this, attrs.token, -1, false);
                 addToken = true;
             } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -1999,6 +2013,15 @@ public class WindowManagerService extends IWindowManager.Stub
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_TOAST) {
+                // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
+                addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
+                        callingUid, attachedWindow);
+                if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
+                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
+                            + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
             } else if (type == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
@@ -2043,6 +2066,35 @@ public class WindowManagerService extends IWindowManager.Stub
                 win.openInputChannel(outInputChannel);
             }
 
+            // If adding a toast requires a token for this app we always schedule hiding
+            // toast windows to make sure they don't stick around longer then necessary.
+            // We hide instead of remove such windows as apps aren't prepared to handle
+            // windows being removed under them.
+            //   If the app is older it can add toasts without a token and hence overlay
+            // other apps. To be maximally compatible with these apps we will hide the
+            // window after the toast timeout only if the focused window is from another
+            // UID, otherwise we allow unlimited duration. When a UID looses focus we
+            // schedule hiding all of its toast windows.
+            if (type == TYPE_TOAST) {
+                if (!canAddToastWindowForUid(getDefaultDisplayContentLocked(), callingUid)) {
+                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
+                    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
+                }
+                // Make sure this happens before we moved focus as one can make the
+                // toast focusable to force it not being hidden after the timeout.
+                // Focusable toasts are always timed out to prevent a focused app to
+                // show a focusable toasts while it has focus which will be kept on
+                // the screen after the activity goes away.
+                if (addToastWindowRequiresToken
+                        || (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
+                        || mCurrentFocus == null
+                        || mCurrentFocus.mOwnerUid != callingUid) {
+                    mH.sendMessageDelayed(
+                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
+                            win.mAttrs.hideTimeoutMilliseconds);
+                }
+            }
+
             // From now on, no exceptions or errors allowed!
 
             res = WindowManagerGlobal.ADD_OKAY;
@@ -2181,11 +2233,6 @@ public class WindowManagerService extends IWindowManager.Stub
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
             }
-            if (attrs.removeTimeoutMilliseconds > 0) {
-                mH.sendMessageDelayed(
-                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
-                        attrs.removeTimeoutMilliseconds);
-            }
         }
 
         if (reportNewConfig) {
@@ -2197,6 +2244,73 @@ public class WindowManagerService extends IWindowManager.Stub
         return res;
     }
 
+    private boolean canAddToastWindowForUid(DisplayContent displayContent, int uid) {
+        // We allow one toast window per UID being shown at a time.
+        WindowList windows = displayContent.getWindowList();
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            WindowState window = windows.get(i);
+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
+                    && !window.mPermanentlyHidden) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
+            WindowState attachedWindow) {
+        // Try using the target SDK of the root window
+        if (attachedWindow != null) {
+            WindowState currentWindow = attachedWindow;
+            while (currentWindow != null) {
+                if (currentWindow.mAppToken != null
+                        && currentWindow.mAppToken.targetSdk > Build.VERSION_CODES.N_MR1) {
+                    return true;
+                }
+                currentWindow = currentWindow.mAttachedWindow;
+            }
+        } else {
+            // Otherwise, look at the package
+            try {
+                ApplicationInfo appInfo = mContext.getPackageManager()
+                        .getApplicationInfoAsUser(packageName, 0,
+                                UserHandle.getUserId(callingUid));
+                if (appInfo.uid != callingUid) {
+                    throw new SecurityException("Package " + packageName + " not in UID "
+                            + callingUid);
+                }
+                if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+                    return true;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                /* ignore */
+            }
+        }
+        return false;
+    }
+
+    private void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
+            WindowState newFocus) {
+        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
+            return;
+        }
+        final int lostFocusUid = oldFocus.mOwnerUid;
+        DisplayContent displayContent = oldFocus.getDisplayContent();
+        WindowList windows = displayContent.getWindowList();
+        final int windowCount = windows.size();
+        for (int i = 0; i < windowCount; i++) {
+            WindowState window = windows.get(i);
+            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
+                if (!mH.hasMessages(H.WINDOW_HIDE_TIMEOUT, window)) {
+                    mH.sendMessageDelayed(
+                            mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, window),
+                            window.mAttrs.hideTimeoutMilliseconds);
+                }
+            }
+        }
+    }
+
     /**
      * Returns true if we're done setting up any transitions.
      */
@@ -8124,7 +8238,7 @@ public class WindowManagerService extends IWindowManager.Stub
         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
         public static final int UPDATE_ANIMATION_SCALE = 51;
-        public static final int WINDOW_REMOVE_TIMEOUT = 52;
+        public static final int WINDOW_HIDE_TIMEOUT = 52;
         public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
 
@@ -8744,7 +8858,7 @@ public class WindowManagerService extends IWindowManager.Stub
                     mAmInternal.notifyStartingWindowDrawn();
                 }
                 break;
-                case WINDOW_REMOVE_TIMEOUT: {
+                case WINDOW_HIDE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized(mWindowMap) {
                         // TODO: This is all about fixing b/21693547
@@ -8755,8 +8869,11 @@ public class WindowManagerService extends IWindowManager.Stub
                         // running under debugger) to crash (b/29105388). The windows will
                         // eventually be removed when the client process finishes.
                         // The best we can do for now is remove the FLAG_KEEP_SCREEN_ON
-                        // and prevent the symptoms of b/21693547.
+                        // and prevent the symptoms of b/21693547. Since apps don't
+                        // support windows being removed under them we hide the window
+                        // and it will be removed when the app dies.
                         window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
+                        window.markPermanentlyHiddenLw();
                         window.setDisplayLayoutNeeded();
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
@@ -9786,6 +9903,11 @@ public class WindowManagerService extends IWindowManager.Stub
 
             adjustForImeIfNeeded(displayContent);
 
+            // We may need to schedule some toast windows to be removed. The
+            // toasts for an app that does not have input focus are removed
+            // within a timeout to prevent apps to redress other apps' UI.
+            scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
+
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             return true;
         }
index a00ac5d..10f01e4 100644 (file)
@@ -165,6 +165,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
     boolean mPolicyVisibility = true;
     boolean mPolicyVisibilityAfterAnim = true;
     boolean mAppOpVisibility = true;
+    boolean mPermanentlyHidden;
     boolean mAppFreezing;
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
@@ -1873,6 +1874,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
             // Being hidden due to app op request.
             return false;
         }
+        if (mPermanentlyHidden) {
+            // Permanently hidden until the app exists as apps aren't prepared
+            // to handle their windows being removed from under them.
+            return false;
+        }
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             // Already showing.
             return false;
@@ -1963,6 +1969,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
         }
     }
 
+    public void markPermanentlyHiddenLw() {
+        if (!mPermanentlyHidden) {
+            mPermanentlyHidden = true;
+            hideLw(true, true);
+        }
+    }
+
     public void pokeDrawLockLw(long timeout) {
         if (isVisibleOrAdding()) {
             if (mDrawLock == null) {
@@ -2612,7 +2625,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
             pw.println(Integer.toHexString(mSystemUiVisibility));
         }
         if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
-                || mAttachedHidden) {
+                || mAttachedHidden || mPermanentlyHidden) {
             pw.print(prefix); pw.print("mPolicyVisibility=");
                     pw.print(mPolicyVisibility);
                     pw.print(" mPolicyVisibilityAfterAnim=");
@@ -2620,6 +2633,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                     pw.print(" mAppOpVisibility=");
                     pw.print(mAppOpVisibility);
                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
+                    pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
         }
         if (!mRelayoutCalled || mLayoutNeeded) {
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);