OSDN Git Service

Merge "DO NOT MERGE: Add dynamic illuminance hysteresis support" into cw-f-dev
authorJulius D'souza <jdsouza@google.com>
Tue, 23 Aug 2016 15:09:08 +0000 (15:09 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 23 Aug 2016 15:09:10 +0000 (15:09 +0000)
29 files changed:
core/java/android/provider/VoicemailContract.java
core/java/android/view/View.java
core/java/android/view/ViewGroup.java
core/java/android/widget/PopupWindow.java
core/res/res/values-mcc232-mnc10/config.xml [new file with mode: 0644]
core/res/res/values-mcc232-mnc13/config.xml [new file with mode: 0644]
core/res/res/values-mcc302-mnc500/config.xml [new file with mode: 0644]
core/res/res/values-mcc302-mnc510/config.xml [new file with mode: 0644]
core/res/res/values/config.xml
core/res/res/values/symbols.xml
docs/html/_redirects.yaml
graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
graphics/java/android/graphics/drawable/VectorDrawable.java
packages/DocumentsUI/src/com/android/documentsui/Events.java
packages/SettingsLib/res/values/strings.xml
packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
packages/SystemUI/res/values-hy-rAM/strings.xml
services/core/java/com/android/server/AnyMotionDetector.java
services/core/java/com/android/server/pm/PackageInstallerSession.java
services/core/java/com/android/server/pm/PackageManagerService.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/net/java/android/net/ip/IpManager.java
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
tools/fonts/fontchain_lint.py

index 27b0a8b..5099eeb 100644 (file)
@@ -30,7 +30,6 @@ import android.provider.CallLog.Calls;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-
 import java.util.List;
 
 /**
@@ -123,22 +122,36 @@ public class VoicemailContract {
             "android.intent.action.VOICEMAIL_SMS_RECEIVED";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * event type of the SMS. Common values are "SYNC" or "STATUS"
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
+     * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
+     * it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
             "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * fields sent by the SMS
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
             "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
 
     /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+     * message body of the SMS. This extra is included if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
+     */
+    /**
+     * @hide
+     */
+    public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
+        "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
+
+    /**
      * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
      * subscription ID of the phone account that received the SMS.
      */
index 51a188b..fb121ac 100644 (file)
@@ -20280,8 +20280,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                 // remove it from the transparent region.
                 final int[] location = attachInfo.mTransparentLocation;
                 getLocationInWindow(location);
-                region.op(location[0], location[1], location[0] + mRight - mLeft,
-                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
+                // When a view has Z value, then it will be better to leave some area below the view
+                // for drawing shadow. The shadow outset is proportional to the Z value. Note that
+                // the bottom part needs more offset than the left, top and right parts due to the
+                // spot light effects.
+                int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
+                region.op(location[0] - shadowOffset, location[1] - shadowOffset,
+                        location[0] + mRight - mLeft + shadowOffset,
+                        location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
             } else {
                 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
                     // The SKIP_DRAW flag IS set and the background drawable exists, we remove
index 3ff8d4f..6933efc 100644 (file)
@@ -6406,16 +6406,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
             return true;
         }
         super.gatherTransparentRegion(region);
-        final View[] children = mChildren;
-        final int count = mChildrenCount;
+        // Instead of naively traversing the view tree, we have to traverse according to the Z
+        // order here. We need to go with the same order as dispatchDraw().
+        // One example is that after surfaceView punch a hole, we will still allow other views drawn
+        // on top of that hole. In this case, those other views should be able to cut the
+        // transparent region into smaller area.
+        final int childrenCount = mChildrenCount;
         boolean noneOfTheChildrenAreTransparent = true;
-        for (int i = 0; i < count; i++) {
-            final View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
-                if (!child.gatherTransparentRegion(region)) {
-                    noneOfTheChildrenAreTransparent = false;
+        if (childrenCount > 0) {
+            final ArrayList<View> preorderedList = buildOrderedChildList();
+            final boolean customOrder = preorderedList == null
+                    && isChildrenDrawingOrderEnabled();
+            final View[] children = mChildren;
+            for (int i = 0; i < childrenCount; i++) {
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
+                    if (!child.gatherTransparentRegion(region)) {
+                        noneOfTheChildrenAreTransparent = false;
+                    }
                 }
             }
+            if (preorderedList != null) preorderedList.clear();
         }
         return meOpaque || noneOfTheChildrenAreTransparent;
     }
index 6432f70..5935c78 100644 (file)
@@ -1547,7 +1547,7 @@ public class PopupWindow {
         }
 
         // Let the window manager know to align the top to y.
-        outParams.gravity = Gravity.LEFT | Gravity.TOP;
+        outParams.gravity = computeGravity();
         outParams.width = width;
         outParams.height = height;
 
diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
new file mode 100644 (file)
index 0000000..bdf8301
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+        <item>23205</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
new file mode 100644 (file)
index 0000000..2c14f87
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
new file mode 100644 (file)
index 0000000..77f6419
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
new file mode 100644 (file)
index 0000000..77f6419
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
index a58f260..ecbc5b5 100644 (file)
 
     <!-- The threshold angle for any motion detection in auto-power save modes.
          In hundreths of a degree. -->
-    <integer name="config_autoPowerModeThresholdAngle">200</integer>
+    <integer name="config_autoPowerModeThresholdAngle">10</integer>
 
     <!-- The sensor id of an "any motion" sensor used in auto-power save modes.
          0 indicates this sensor is not available. -->
 
     <string name="config_networkOverLimitComponent" translatable="false">com.android.systemui/com.android.systemui.net.NetworkOverLimitActivity</string>
     <string name="config_dataUsageSummaryComponent" translatable="false">com.android.settings/com.android.settings.Settings$DataUsageSummaryActivity</string>
+
+    <!-- A array of regex to treat a SMS as VVM SMS if the message body matches.
+         Each item represents an entry, which consists of two parts:
+         a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and
+         then the regex itself. -->
+    <string-array translatable="false" name="config_vvmSmsFilterRegexes">
+        <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
+        <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
+    </string-array>
 </resources>
index ce967b0..87d3eb4 100644 (file)
   <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
   <java-symbol type="id" name="profile_button" />
 
+  <java-symbol type="array" name="config_vvmSmsFilterRegexes" />
+
   <!-- Cascading submenus -->
   <java-symbol type="dimen" name="cascading_menus_min_smallest_width" />
 
index a158114..e28b8e6 100644 (file)
@@ -25,6 +25,8 @@ redirects:
   to: /topic/libraries/support-library/index.html
 - from: /billions
   to: /topic/billions/index.html
+- from: /performance
+  to: /topic/performance/index.html
 - from: /tools/extras/support-library.html
   to: /topic/libraries/support-library/index.html
 - from: /training/basics/fragments/support-lib.html
index c836204..0f305f3 100644 (file)
@@ -144,6 +144,55 @@ import java.util.ArrayList;
  *         android:valueType=&quot;pathType&quot;/&gt;
  * &lt;/set&gt;
  * </pre></li>
+ * <p>
+ * Since AAPT tool is now supporting a new format which can bundle several related XML files into
+ * one, we can merge the previous example into one XML file, like this:
+ * </p>
+ * <pre>
+ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
+ *     &lt;aapt:attr name="android:drawable"&gt;
+ *         &lt;vector
+ *             android:height=&quot;64dp&quot;
+ *             android:width=&quot;64dp&quot;
+ *             android:viewportHeight=&quot;600&quot;
+ *             android:viewportWidth=&quot;600&quot; &gt;
+ *             &lt;group
+ *                 android:name=&quot;rotationGroup&quot;
+ *                 android:pivotX=&quot;300.0&quot;
+ *                 android:pivotY=&quot;300.0&quot;
+ *                 android:rotation=&quot;45.0&quot; &gt;
+ *                 &lt;path
+ *                     android:name=&quot;v&quot;
+ *                     android:fillColor=&quot;#000000&quot;
+ *                     android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
+ *             &lt;/group&gt;
+ *         &lt;/vector&gt;
+ *     &lt;/aapt:attr&gt;
+ *
+ *     &lt;target android:name=&quot;rotationGroup&quot;&gt; *
+ *         &lt;aapt:attr name="android:animation"&gt;
+ *             &lt;objectAnimator
+ *             android:duration=&quot;6000&quot;
+ *             android:propertyName=&quot;rotation&quot;
+ *             android:valueFrom=&quot;0&quot;
+ *             android:valueTo=&quot;360&quot; /&gt;
+ *         &lt;/aapt:attr&gt;
+ *     &lt;/target&gt;
+ *
+ *     &lt;target android:name=&quot;v&quot; &gt;
+ *         &lt;aapt:attr name="android:animation"&gt;
+ *             &lt;set&gt;
+ *                 &lt;objectAnimator
+ *                     android:duration=&quot;3000&quot;
+ *                     android:propertyName=&quot;pathData&quot;
+ *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
+ *                     android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
+ *                     android:valueType=&quot;pathType&quot;/&gt;
+ *             &lt;/set&gt;
+ *         &lt;/aapt:attr&gt;
+ *      &lt;/target&gt;
+ * &lt;/animated-vector&gt;
+ * </pre>
  *
  * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
  * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
index dc1d18f..9ff6965 100644 (file)
@@ -27,9 +27,9 @@ import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Shader;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
@@ -140,12 +140,16 @@ import dalvik.system.VMRuntime;
  * in the SVG's path data. This is defined in the viewport space.</dd>
  * <dt><code>android:fillColor</code></dt>
  * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list
- * or a gradient color. If this property is animated, any value set by the animation will
- * override the original value. No path fill is drawn if this property is not specified.</dd>
+ * or a gradient color (See {@link android.R.styleable#GradientColor}
+ * and {@link android.R.styleable#GradientColorItem}).
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path fill is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeColor</code></dt>
  * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color
- * state list or a gradient color. If this property is animated, any value set by the animation will
- * override the original value. No path outline is drawn if this property is not specified.</dd>
+ * state list or a gradient color (See {@link android.R.styleable#GradientColor}
+ * and {@link android.R.styleable#GradientColorItem}).
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path outline is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeWidth</code></dt>
  * <dd>The width a path stroke.</dd>
  * <dt><code>android:strokeAlpha</code></dt>
@@ -166,8 +170,9 @@ import dalvik.system.VMRuntime;
  * <dt><code>android:strokeMiterLimit</code></dt>
  * <dd>Sets the Miter limit for a stroked path.</dd>
  * <dt><code>android:fillType</code></dt>
- * <dd>Sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
- * For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty</dd>
+ * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
+ * same as SVG's "fill-rule" properties. For more details, see
+ * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
  * </dl></dd>
  * </dl>
  *
@@ -201,7 +206,26 @@ import dalvik.system.VMRuntime;
  *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
  *     &lt;/group&gt;
  * &lt;/vector&gt;
- * </pre></li>
+ * </pre>
+ * </li>
+ * <li>And here is an example of linear gradient color, which is supported in SDK 24+.
+ * See more details in {@link android.R.styleable#GradientColor} and
+ * {@link android.R.styleable#GradientColorItem}.
+ * <pre>
+ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:angle="90"
+ *     android:startColor="?android:attr/colorPrimary"
+ *     android:endColor="?android:attr/colorControlActivated"
+ *     android:centerColor="#f00"
+ *     android:startX="0"
+ *     android:startY="0"
+ *     android:endX="100"
+ *     android:endY="100"
+ *     android:type="linear"&gt;
+ * &lt;/gradient&gt;
+ * </pre>
+ * </li>
+ *
  */
 
 public class VectorDrawable extends Drawable {
index 14d4e2d..02a9127 100644 (file)
@@ -53,7 +53,8 @@ public final class Events {
      */
     public static boolean isTouchType(int toolType) {
         return toolType == MotionEvent.TOOL_TYPE_FINGER
-                || toolType == MotionEvent.TOOL_TYPE_STYLUS;
+                || toolType == MotionEvent.TOOL_TYPE_STYLUS
+                || toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
     }
 
     /**
index 7d42211..682af8b 100644 (file)
     <!-- Label for Help and feedback menu item -->
     <string name="help_feedback_label">Help &amp; feedback</string>
 
+    <!-- Content description for drawer menu button [CHAR_LIMIT=30]-->
+    <string name="content_description_menu_button">Menu</string>
+
 </resources>
index 6658c14..a50b366 100644 (file)
@@ -226,6 +226,7 @@ public class SettingsDrawerActivity extends Activity {
     public void showMenuIcon() {
         mShowingMenu = true;
         getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
+        getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
         getActionBar().setDisplayHomeAsUpEnabled(true);
     }
 
index 284827b..aae9cf6 100644 (file)
@@ -29,7 +29,6 @@ import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.widget.TextView;
-
 import com.android.settingslib.R;
 
 public class AccessPointPreference extends Preference {
@@ -44,13 +43,14 @@ public class AccessPointPreference extends Preference {
     private final StateListDrawable mWifiSld;
     private final int mBadgePadding;
     private final UserBadgeCache mBadgeCache;
-
     private TextView mTitleView;
+
     private boolean mForSavedNetworks = false;
     private AccessPoint mAccessPoint;
     private Drawable mBadge;
     private int mLevel;
     private CharSequence mContentDescription;
+    private int mDefaultIconResId;
 
     static final int[] WIFI_CONNECTION_STRENGTH = {
             R.string.accessibility_wifi_one_bar,
@@ -85,6 +85,24 @@ public class AccessPointPreference extends Preference {
         refresh();
     }
 
+    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
+            int iconResId, boolean forSavedNetworks) {
+        super(context);
+        mBadgeCache = cache;
+        mAccessPoint = accessPoint;
+        mForSavedNetworks = forSavedNetworks;
+        mAccessPoint.setTag(this);
+        mLevel = -1;
+        mDefaultIconResId = iconResId;
+
+        mWifiSld = (StateListDrawable) context.getTheme()
+                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+
+        // Distance from the end of the title at which this AP's user badge should sit.
+        mBadgePadding = context.getResources()
+                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
+    }
+
     public AccessPoint getAccessPoint() {
         return mAccessPoint;
     }
@@ -112,7 +130,7 @@ public class AccessPointPreference extends Preference {
 
     protected void updateIcon(int level, Context context) {
         if (level == -1) {
-            setIcon(null);
+            safeSetDefaultIcon();
         } else {
             if (getIcon() == null) {
                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
@@ -124,16 +142,24 @@ public class AccessPointPreference extends Preference {
                             ? STATE_SECURED
                             : STATE_NONE);
                     Drawable drawable = mWifiSld.getCurrent();
-                    if (!mForSavedNetworks) {
+                    if (!mForSavedNetworks && drawable != null) {
                         setIcon(drawable);
-                    } else {
-                        setIcon(null);
+                        return;
                     }
                 }
+                safeSetDefaultIcon();
             }
         }
     }
 
+    private void safeSetDefaultIcon() {
+        if (mDefaultIconResId != 0) {
+            setIcon(mDefaultIconResId);
+        } else {
+            setIcon(null);
+        }
+    }
+
     protected void updateBadge(Context context) {
         WifiConfiguration config = mAccessPoint.getConfig();
         if (config != null) {
index d0d6c50..2aad63c 100644 (file)
@@ -32,7 +32,7 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
-    <string name="battery_low_title" msgid="6456385927409742437">"Õ\84Õ¡Ö\80Õ¿Õ¯Õ¸Ö\81Õ¨ Õ¬Õ«Ö\81Ö\84Õ¡Õ©Õ¡Ö\83վում է"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Õ\84Õ¡Ö\80Õ¿Õ¯Õ¸Ö\81Õ« Õ¬Õ«Ö\81Ö\84Õ¨ Õ½ÕºÕ¡Õ¼վում է"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
index f93c716..d564925 100644 (file)
@@ -97,6 +97,15 @@ public class AnyMotionDetector {
     /** True if an orientation measurement is in progress. */
     private boolean mMeasurementInProgress;
 
+    /** True if sendMessageDelayed() for the mMeasurementTimeout callback has been scheduled */
+    private boolean mMeasurementTimeoutIsActive;
+
+    /** True if sendMessageDelayed() for the mWakelockTimeout callback has been scheduled */
+    private boolean mWakelockTimeoutIsActive;
+
+    /** True if sendMessageDelayed() for the mSensorRestart callback has been scheduled */
+    private boolean mSensorRestartIsActive;
+
     /** The most recent gravity vector. */
     private Vector3 mCurrentGravityVector = null;
 
@@ -118,6 +127,9 @@ public class AnyMotionDetector {
             mSensorManager = sm;
             mAccelSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
             mMeasurementInProgress = false;
+            mMeasurementTimeoutIsActive = false;
+            mWakelockTimeoutIsActive = false;
+            mSensorRestartIsActive = false;
             mState = STATE_INACTIVE;
             mCallback = callback;
             mThresholdAngle = thresholdAngle;
@@ -146,6 +158,7 @@ public class AnyMotionDetector {
                 mWakeLock.acquire();
                 Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout);
                 mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS);
+                mWakelockTimeoutIsActive = true;
                 startOrientationMeasurementLocked();
             }
         }
@@ -157,17 +170,20 @@ public class AnyMotionDetector {
                 mState = STATE_INACTIVE;
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE.");
             }
+            mHandler.removeCallbacks(mMeasurementTimeout);
+            mHandler.removeCallbacks(mSensorRestart);
+            mMeasurementTimeoutIsActive = false;
+            mSensorRestartIsActive = false;
             if (mMeasurementInProgress) {
                 mMeasurementInProgress = false;
                 mSensorManager.unregisterListener(mListener);
             }
-            mHandler.removeCallbacks(mMeasurementTimeout);
-            mHandler.removeCallbacks(mSensorRestart);
             mCurrentGravityVector = null;
             mPreviousGravityVector = null;
             if (mWakeLock.isHeld()) {
-                mWakeLock.release();
                 mHandler.removeCallbacks(mWakelockTimeout);
+                mWakelockTimeoutIsActive = false;
+                mWakeLock.release();
             }
         }
     }
@@ -183,6 +199,7 @@ public class AnyMotionDetector {
             }
             Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout);
             mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
+            mMeasurementTimeoutIsActive = true;
         }
     }
 
@@ -191,8 +208,9 @@ public class AnyMotionDetector {
                 mMeasurementInProgress);
         int status = RESULT_UNKNOWN;
         if (mMeasurementInProgress) {
-            mSensorManager.unregisterListener(mListener);
             mHandler.removeCallbacks(mMeasurementTimeout);
+            mMeasurementTimeoutIsActive = false;
+            mSensorManager.unregisterListener(mListener);
             mMeasurementInProgress = false;
             mPreviousGravityVector = mCurrentGravityVector;
             mCurrentGravityVector = mRunningStats.getRunningAverage();
@@ -213,8 +231,9 @@ public class AnyMotionDetector {
             if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status);
             if (status != RESULT_UNKNOWN) {
                 if (mWakeLock.isHeld()) {
-                    mWakeLock.release();
                     mHandler.removeCallbacks(mWakelockTimeout);
+                    mWakelockTimeoutIsActive = false;
+                    mWakeLock.release();
                 }
                 if (DEBUG) {
                     Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " + status);
@@ -230,6 +249,7 @@ public class AnyMotionDetector {
                         " milliseconds.");
                 Message msg = Message.obtain(mHandler, mSensorRestart);
                 mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS);
+                mSensorRestartIsActive = true;
             }
         }
         return status;
@@ -283,6 +303,7 @@ public class AnyMotionDetector {
             }
             if (status != RESULT_UNKNOWN) {
                 mHandler.removeCallbacks(mWakelockTimeout);
+                mWakelockTimeoutIsActive = false;
                 mCallback.onAnyMotionResult(status);
             }
         }
@@ -296,7 +317,10 @@ public class AnyMotionDetector {
         @Override
         public void run() {
             synchronized (mLock) {
-                startOrientationMeasurementLocked();
+                if (mSensorRestartIsActive == true) {
+                    mSensorRestartIsActive = false;
+                    startOrientationMeasurementLocked();
+                }
             }
         }
     };
@@ -306,14 +330,18 @@ public class AnyMotionDetector {
         public void run() {
             int status = RESULT_UNKNOWN;
             synchronized (mLock) {
-                if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
-                      "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
-                      "orientation measurement.");
-                status = stopOrientationMeasurementLocked();
-            }
-            if (status != RESULT_UNKNOWN) {
-                mHandler.removeCallbacks(mWakelockTimeout);
-                mCallback.onAnyMotionResult(status);
+                if (mMeasurementTimeoutIsActive == true) {
+                    mMeasurementTimeoutIsActive = false;
+                    if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
+                          "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
+                          "orientation measurement.");
+                    status = stopOrientationMeasurementLocked();
+                    if (status != RESULT_UNKNOWN) {
+                        mHandler.removeCallbacks(mWakelockTimeout);
+                        mWakelockTimeoutIsActive = false;
+                        mCallback.onAnyMotionResult(status);
+                    }
+                }
             }
         }
     };
@@ -322,7 +350,10 @@ public class AnyMotionDetector {
         @Override
         public void run() {
             synchronized (mLock) {
-                stop();
+                if (mWakelockTimeoutIsActive == true) {
+                    mWakelockTimeoutIsActive = false;
+                    stop();
+                }
             }
         }
     };
index 6cdc40f..5831284 100644 (file)
@@ -109,6 +109,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     final int installerUid;
     final SessionParams params;
     final long createdMillis;
+    final int defaultContainerGid;
 
     /** Staging location where client data is written. */
     final File stageDir;
@@ -199,13 +200,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
+            // Cache package manager data without the lock held
+            final PackageInfo pkgInfo = mPm.getPackageInfo(
+                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
+            final ApplicationInfo appInfo = mPm.getApplicationInfo(
+                    params.appPackageName, 0, userId);
+
             synchronized (mLock) {
                 if (msg.obj != null) {
                     mRemoteObserver = (IPackageInstallObserver2) msg.obj;
                 }
 
                 try {
-                    commitLocked();
+                    commitLocked(pkgInfo, appInfo);
                 } catch (PackageManagerException e) {
                     final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                     Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
@@ -264,6 +271,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
         } else {
             mPermissionsAccepted = false;
         }
+        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
+                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+        defaultContainerGid = UserHandle.getSharedAppGid(uid);
     }
 
     public SessionInfo generateInfo() {
@@ -520,7 +530,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
     }
 
-    private void commitLocked() throws PackageManagerException {
+    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         if (mDestroyed) {
             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
         }
@@ -538,7 +549,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
         // Verify that stage looks sane with respect to existing application.
         // This currently only ensures packageName, versionCode, and certificate
         // consistency.
-        validateInstallLocked();
+        validateInstallLocked(pkgInfo, appInfo);
 
         Preconditions.checkNotNull(mPackageName);
         Preconditions.checkNotNull(mSignatures);
@@ -650,7 +661,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
      * Note that upgrade compatibility is still performed by
      * {@link PackageManagerService}.
      */
-    private void validateInstallLocked() throws PackageManagerException {
+    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         mPackageName = null;
         mVersionCode = -1;
         mSignatures = null;
@@ -729,10 +741,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
 
         if (removeSplitList.size() > 0) {
             // validate split names marked for removal
-            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
-            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
             for (String splitName : removeSplitList) {
-                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
+                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Split not found: " + splitName);
                 }
@@ -740,11 +750,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
 
             // ensure we've got appropriate package name, version code and signatures
             if (mPackageName == null) {
-                mPackageName = pkg.packageName;
-                mVersionCode = pkg.versionCode;
+                mPackageName = pkgInfo.packageName;
+                mVersionCode = pkgInfo.versionCode;
             }
             if (mSignatures == null) {
-                mSignatures = pkg.signatures;
+                mSignatures = pkgInfo.signatures;
             }
         }
 
@@ -757,8 +767,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
 
         } else {
             // Partial installs must be consistent with existing install
-            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
-            if (app == null) {
+            if (appInfo == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Missing existing base package for " + mPackageName);
             }
@@ -766,8 +775,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
             final PackageLite existing;
             final ApkLite existingBase;
             try {
-                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
-                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
+                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
+                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -777,7 +786,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
 
             // Inherit base if not overridden
             if (mResolvedBaseFile == null) {
-                mResolvedBaseFile = new File(app.getBaseCodePath());
+                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 mResolvedInheritedFiles.add(mResolvedBaseFile);
             }
 
@@ -794,7 +803,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
             }
 
             // Inherit compiled oat directory.
-            final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile();
+            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
             mInheritedFilesBase = packageInstallDir;
             final File oatDir = new File(packageInstallDir, "oat");
             if (oatDir.exists()) {
@@ -822,7 +831,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
         }
     }
 
-    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
+    private void assertApkConsistent(String tag, ApkLite apk)
+            throws PackageManagerException {
         if (!mPackageName.equals(apk.packageName)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
                     + apk.packageName + " inconsistent with " + mPackageName);
@@ -1035,10 +1045,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                     "Failed to finalize container " + cid);
         }
 
-        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-        final int gid = UserHandle.getSharedAppGid(uid);
-        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
+        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
                     "Failed to fix permissions on container " + cid);
         }
index f326555..005c6b3 100644 (file)
@@ -8649,7 +8649,9 @@ public class PackageManagerService extends IPackageManager.Stub {
             for (i=0; i<N; i++) {
                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
-                if (cur == null) {
+                final String curPackageName = cur == null ? null : cur.info.packageName;
+                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+                if (cur == null || isPackageUpdate) {
                     mPermissionGroups.put(pg.info.name, pg);
                     if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
                         if (r == null) {
@@ -8657,6 +8659,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                         } else {
                             r.append(' ');
                         }
+                        if (isPackageUpdate) {
+                            r.append("UPD:");
+                        }
                         r.append(pg.info.name);
                     }
                 } else {
index c1fc7f1..b80775b 100644 (file)
@@ -324,9 +324,29 @@ public class ShortcutService extends IShortcutService.Stub {
         int CHECK_LAUNCHER_ACTIVITY = 12;
         int IS_ACTIVITY_ENABLED = 13;
         int PACKAGE_UPDATE_CHECK = 14;
-
-        int COUNT = PACKAGE_UPDATE_CHECK + 1;
-    }
+        int ASYNC_PRELOAD_USER_DELAY = 15;
+
+        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
+    }
+
+    private static final String[] STAT_LABELS = {
+            "getHomeActivities()",
+            "Launcher permission check",
+            "getPackageInfo()",
+            "getPackageInfo(SIG)",
+            "getApplicationInfo",
+            "cleanupDanglingBitmaps",
+            "getActivity+metadata",
+            "getInstalledPackages",
+            "checkPackageChanges",
+            "getApplicationResources",
+            "resourceNameLookup",
+            "getLauncherActivity",
+            "checkLauncherActivity",
+            "isActivityEnabled",
+            "packageUpdateCheck",
+            "asyncPreloadUserDelay"
+    };
 
     final Object mStatLock = new Object();
 
@@ -533,19 +553,26 @@ public class ShortcutService extends IShortcutService.Stub {
     /** lifecycle event */
     void handleUnlockUser(int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "handleUnlockUser: user=" + userId);
+        Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mLock) {
             mUnlockedUsers.put(userId, true);
-
-            // Preload the user's shortcuts.
-            // Also see if the locale has changed.
-            // Note as of nyc, the locale is per-user, so the locale shouldn't change
-            // when the user is locked.  However due to b/30119489 it still happens.
-            getUserShortcutsLocked(userId).detectLocaleChange();
-
-            checkPackageChanges(userId);
         }
+
+        // Preload the user data.
+        // Note, we don't use mHandler here but instead just start a new thread.
+        // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
+        // busy at this point and this could take hundreds of milliseconds, which would be too
+        // late since the launcher would already have started.
+        // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
+        // or anything.
+        final long start = injectElapsedRealtime();
+        injectRunOnNewThread(() -> {
+            synchronized (mLock) {
+                logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
+                getUserShortcutsLocked(userId);
+            }
+        });
     }
 
     /** lifecycle event */
@@ -1110,6 +1137,9 @@ public class ShortcutService extends IShortcutService.Stub {
                 userPackages = new ShortcutUser(this, userId);
             }
             mUsers.put(userId, userPackages);
+
+            // Also when a user's data is first accessed, scan all packages.
+            checkPackageChanges(userId);
         }
         return userPackages;
     }
@@ -1468,6 +1498,10 @@ public class ShortcutService extends IShortcutService.Stub {
         mHandler.post(r);
     }
 
+    void injectRunOnNewThread(Runnable r) {
+        new Thread(r).start();
+    }
+
     /**
      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
      *                                  {@link #getMaxActivityShortcuts()}.
@@ -3218,23 +3252,9 @@ public class ShortcutService extends IShortcutService.Stub {
 
             pw.println("  Stats:");
             synchronized (mStatLock) {
-                final String p = "    ";
-                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
-                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
-
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
-                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
-                dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
-                dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
-                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
-                dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
-                dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
-                dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
-                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
-                dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
+                for (int i = 0; i < Stats.COUNT; i++) {
+                    dumpStatLS(pw, "    ", i);
+                }
             }
 
             pw.println();
@@ -3277,12 +3297,12 @@ public class ShortcutService extends IShortcutService.Stub {
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
 
-    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
         pw.print(prefix);
         final int count = mCountStats[statId];
         final long dur = mDurationStats[statId];
         pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
-                label, count, dur,
+                STAT_LABELS[statId], count, dur,
                 (count == 0 ? 0 : ((double) dur) / count)));
     }
 
index 1c303dc..8536a2d 100644 (file)
@@ -7828,6 +7828,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         }
 
         final WindowState w = mTopFullscreenOpaqueWindowState;
+        if (w != mFocusedWindow) {
+            return false;
+        }
 
         // We only enable seamless rotation if the top window has requested
         // it and is in the fullscreen opaque state. Seamless rotation
index f2f85bf..1f82f0c 100644 (file)
@@ -2908,12 +2908,11 @@ public class WindowManagerService extends IWindowManager.Stub
                     }
                     result |= RELAYOUT_RES_SURFACE_CHANGED;
                 }
-                final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
-                if (viewVisibility == View.VISIBLE && surfaceController != null) {
+                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
                     // We already told the client to go invisible, but the message may not be
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
-                    surfaceController.getSurface(outSurface);
+                    winAnimator.mSurfaceController.getSurface(outSurface);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
 
index 654ef18..6d90203 100644 (file)
@@ -382,6 +382,7 @@ public class IpManager extends StateMachine {
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
     private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
 
     private final String mTag;
     private final Context mContext;
@@ -476,6 +477,7 @@ public class IpManager extends StateMachine {
         // Super simple StateMachine.
         addState(mStoppedState);
         addState(mStartedState);
+            addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
@@ -570,7 +572,7 @@ public class IpManager extends StateMachine {
         pw.decreaseIndent();
 
         pw.println();
-        pw.println("StateMachine dump:");
+        pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
@@ -768,6 +770,11 @@ public class IpManager extends StateMachine {
         //         - IPv6 addresses
         //         - IPv6 routes
         //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpManager its own netlink socket(s)
+        // so as to track all required information directly.
         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
@@ -939,16 +946,30 @@ public class IpManager extends StateMachine {
         return true;
     }
 
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        try {
+            mNwService.disableIpv6(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to disable IPv6" + e);
+        }
+
+        try {
+            mNwService.clearInterfaceAddresses(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to clear addresses " + e);
+        }
+    }
+
 
     class StoppedState extends State {
         @Override
         public void enter() {
-            try {
-                mNwService.disableIpv6(mInterfaceName);
-                mNwService.clearInterfaceAddresses(mInterfaceName);
-            } catch (Exception e) {
-                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
-            }
+            stopAllIP();
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
@@ -1023,12 +1044,71 @@ public class IpManager extends StateMachine {
     }
 
     class StartedState extends State {
-        private boolean mDhcpActionInFlight;
-
         @Override
         public void enter() {
             mStartTimeMillis = SystemClock.elapsedRealtime();
 
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                transitionTo(mRunningState);
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpManager restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+            return HANDLED;
+        }
+
+        boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() &&
+                    !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                     mCallback, mMulticastFiltering);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
@@ -1037,12 +1117,6 @@ public class IpManager extends StateMachine {
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
             if (mConfiguration.mEnableIPv6) {
                 // TODO: Consider transitionTo(mStoppingState) if this fails.
                 startIPv6();
@@ -1070,7 +1144,6 @@ public class IpManager extends StateMachine {
 
         @Override
         public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
             stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
@@ -1167,10 +1240,6 @@ public class IpManager extends StateMachine {
                     break;
                 }
 
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
index 1c7a138..e96e97b 100644 (file)
@@ -390,6 +390,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
         }
 
         @Override
+        void injectRunOnNewThread(Runnable r) {
+            runOnHandler(r);
+        }
+
+        @Override
         void injectEnforceCallingPermission(String permission, String message) {
             if (!mCallerPermissions.contains(permission)) {
                 throw new SecurityException("Missing permission: " + permission);
@@ -921,6 +926,12 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
         });
     }
 
+    protected void setPackageLastUpdateTime(String packageName, long value) {
+        updatePackageInfo(packageName, pi -> {
+            pi.lastUpdateTime = value;
+        });
+    }
+
     protected void uninstallPackage(int userId, String packageName) {
         if (ENABLE_DUMP) {
             Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
index 253334e..ed4e391 100644 (file)
@@ -3945,11 +3945,11 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         mInjectedPackages.remove(CALLING_PACKAGE_1);
         mInjectedPackages.remove(CALLING_PACKAGE_3);
 
-        mService.handleUnlockUser(USER_0);
+        mService.checkPackageChanges(USER_0);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));  // ---------------
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
@@ -3961,7 +3961,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
         assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
 
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4154,7 +4154,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         updatePackageVersion(CALLING_PACKAGE_1, 1);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
 
         waitOnMainThread();
@@ -4186,10 +4186,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         mInjectedCurrentTimeMillis = START_TIME + 200;
 
         mRunningUsers.put(USER_10, true);
+        mUnlockedUsers.put(USER_10, true);
 
         reset(c0);
         reset(c10);
+        setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis);
         mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4221,7 +4224,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         // Then send the broadcast, to only user-0.
                 mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4243,9 +4246,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         updatePackageVersion(CALLING_PACKAGE_3, 100);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
index 43d2a1f..a04034e 100644 (file)
@@ -535,6 +535,18 @@ public class VoiceInteractionManagerService extends SystemService {
                     + " user=" + userHandle);
         }
 
+        ComponentName getCurAssistant(int userHandle) {
+            String curAssistant = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ASSISTANT, userHandle);
+            if (TextUtils.isEmpty(curAssistant)) {
+                return null;
+            }
+            if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
+                    + " user=" + userHandle);
+            return ComponentName.unflattenFromString(curAssistant);
+        }
+
         void resetCurAssistant(int userHandle) {
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
                     Settings.Secure.ASSISTANT, null, userHandle);
@@ -1178,6 +1190,7 @@ public class VoiceInteractionManagerService extends SystemService {
                 synchronized (VoiceInteractionManagerServiceStub.this) {
                     ComponentName curInteractor = getCurInteractor(userHandle);
                     ComponentName curRecognizer = getCurRecognizer(userHandle);
+                    ComponentName curAssistant = getCurAssistant(userHandle);
                     if (curRecognizer == null) {
                         // Could a new recognizer appear when we don't have one pre-installed?
                         if (anyPackagesAppearing()) {
@@ -1196,6 +1209,7 @@ public class VoiceInteractionManagerService extends SystemService {
                             // the default config.
                             setCurInteractor(null, userHandle);
                             setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
                             initForUser(userHandle);
                             return;
                         }
@@ -1212,6 +1226,20 @@ public class VoiceInteractionManagerService extends SystemService {
                         return;
                     }
 
+                    if (curAssistant != null) {
+                        int change = isPackageDisappearing(curAssistant.getPackageName());
+                        if (change == PACKAGE_PERMANENT_CHANGE) {
+                            // If the currently set assistant is being removed, then we should
+                            // reset back to the default state (which is probably that we prefer
+                            // to have the default full voice interactor enabled).
+                            setCurInteractor(null, userHandle);
+                            setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
+                            initForUser(userHandle);
+                            return;
+                        }
+                    }
+
                     // There is no interactor, so just deal with a simple recognizer.
                     int change = isPackageDisappearing(curRecognizer.getPackageName());
                     if (change == PACKAGE_PERMANENT_CHANGE
index 336fce9..7ec46a3 100755 (executable)
@@ -507,12 +507,46 @@ def compute_expected_emoji():
     all_sequences = set()
     all_sequences.update(_emoji_variation_sequences)
 
+    # add zwj sequences not in the current emoji-zwj-sequences.txt
+    adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences)
+    adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences)
+    # single parent families
+    additional_emoji_zwj = (
+        (0x1F468, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467),
+        (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467),
+        (0x1F469, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467),
+        (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467),
+    )
+    # sequences formed from man and woman and optional fitzpatrick modifier
+    modified_extensions = (
+        0x2696,
+        0x2708,
+        0x1F3A8,
+        0x1F680,
+        0x1F692,
+    )
+    for seq in additional_emoji_zwj:
+        adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+    for ext in modified_extensions:
+        for base in (0x1F468, 0x1F469):
+            seq = (base, 0x200D, ext)
+            adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+            for modifier in range(0x1F3FB, 0x1F400):
+                seq = (base, modifier, 0x200D, ext)
+                adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+
     for sequence in _emoji_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)
 
-    for sequence in _emoji_zwj_sequences.keys():
+    for sequence in adjusted_emoji_zwj_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)