OSDN Git Service

Merge "Use startActivityDismissingKeyguard to show vpn setting page in keyguard"...
authorTony Mak <tonymak@google.com>
Mon, 13 Jun 2016 12:22:45 +0000 (12:22 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Mon, 13 Jun 2016 12:22:47 +0000 (12:22 +0000)
66 files changed:
core/java/android/app/Activity.java
core/java/android/app/ActivityThread.java
core/java/android/app/LoadedApk.java
core/java/android/app/WallpaperManager.java
core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
core/java/android/hardware/camera2/marshal/MarshalRegistry.java
core/java/android/os/BatteryStats.java
core/java/android/os/RecoverySystem.java
core/java/android/view/SurfaceControl.java
core/java/android/view/ViewRootImpl.java
core/java/android/view/accessibility/AccessibilityWindowInfo.java
core/java/com/android/internal/os/BatteryStatsImpl.java
core/java/com/android/internal/policy/DecorView.java
core/java/com/android/internal/policy/PhoneWindow.java
core/jni/android_view_SurfaceControl.cpp
core/res/AndroidManifest.xml
core/res/res/values-az-rAZ/strings.xml
core/res/res/values-de/strings.xml
core/res/res/values-es-rUS/strings.xml
core/res/res/values-gl-rES/strings.xml
core/res/res/values-hy-rAM/strings.xml
core/res/res/values-nb/strings.xml
core/res/res/values-pa-rIN/strings.xml
core/res/res/values/themes.xml
docs/html/guide/practices/screens_support.jd
docs/html/topic/libraries/support-library/features.jd
docs/html/topic/libraries/testing-support-library/index.jd
docs/html/training/appbar/setting-up.jd
docs/html/training/testing/performance.jd
libs/hwui/Android.mk
libs/hwui/BakedOpRenderer.cpp
libs/hwui/FrameBuilder.cpp
libs/hwui/RenderNode.cpp
libs/hwui/RenderProperties.h
libs/hwui/tests/unit/RenderPropertiesTests.cpp [new file with mode: 0644]
packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
packages/PrintRecommendationService/res/values/strings.xml
packages/PrintRecommendationService/res/xml/vendorconfigs.xml
packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
packages/SettingsLib/res/values-tl/strings.xml
packages/Shell/AndroidManifest.xml
packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
packages/SystemUI/src/com/android/systemui/qs/QSTile.java
packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
services/backup/java/com/android/server/backup/BackupManagerService.java
services/core/java/com/android/server/BluetoothManagerService.java
services/core/java/com/android/server/LocationManagerService.java
services/core/java/com/android/server/MountService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/am/ActivityStarter.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/UserManagerService.java
services/core/java/com/android/server/policy/PhoneWindowManager.java
services/core/java/com/android/server/wm/AccessibilityController.java
services/core/java/com/android/server/wm/WindowStateAnimator.java
services/core/java/com/android/server/wm/WindowSurfaceController.java

index a5fcec6..13cf46d 100644 (file)
@@ -57,6 +57,7 @@ import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.net.Uri;
+import android.os.BadParcelableException;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -5006,13 +5007,18 @@ public class Activity extends ContextThemeWrapper
     @Nullable
     public Uri getReferrer() {
         Intent intent = getIntent();
-        Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
-        if (referrer != null) {
-            return referrer;
-        }
-        String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
-        if (referrerName != null) {
-            return Uri.parse(referrerName);
+        try {
+            Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+            if (referrer != null) {
+                return referrer;
+            }
+            String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+            if (referrerName != null) {
+                return Uri.parse(referrerName);
+            }
+        } catch (BadParcelableException e) {
+            Log.w(TAG, "Cannot read referrer from intent;"
+                    + " intent extras contain unknown custom Parcelable objects");
         }
         if (mReferrer != null) {
             return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
index 2c2f6c1..0728bdf 100644 (file)
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
@@ -4578,20 +4580,37 @@ public final class ActivityThread {
     }
 
     /**
+     * Creates a new Configuration only if override would modify base. Otherwise returns base.
+     * @param base The base configuration.
+     * @param override The update to apply to the base configuration. Can be null.
+     * @return A Configuration representing base with override applied.
+     */
+    private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
+            @Nullable Configuration override) {
+        if (override == null) {
+            return base;
+        }
+        Configuration newConfig = new Configuration(base);
+        newConfig.updateFrom(override);
+        return newConfig;
+    }
+
+    /**
      * Decides whether to update an Activity's configuration and whether to tell the
      * Activity/Component about it.
      * @param cb The component callback to notify of configuration change.
      * @param activityToken The Activity binder token for which this configuration change happened.
      *                      If the change is global, this is null.
      * @param newConfig The new configuration.
-     * @param overrideConfig The override config that differentiates the Activity's configuration
+     * @param amOverrideConfig The override config that differentiates the Activity's configuration
      *                       from the base global configuration.
+     *                       This is supplied by ActivityManager.
      * @param reportToActivity Notify the Activity of the change.
      */
     private void performConfigurationChanged(ComponentCallbacks2 cb,
                                              IBinder activityToken,
                                              Configuration newConfig,
-                                             Configuration overrideConfig,
+                                             Configuration amOverrideConfig,
                                              boolean reportToActivity) {
         // Only for Activity objects, check that they actually call up to their
         // superclass implementation.  ComponentCallbacks2 is an interface, so
@@ -4605,7 +4624,6 @@ public final class ActivityThread {
         if ((activity == null) || (activity.mCurrentConfig == null)) {
             shouldChangeConfig = true;
         } else {
-
             // If the new config is the same as the config this Activity
             // is already running with then don't bother calling
             // onConfigurationChanged
@@ -4615,34 +4633,36 @@ public final class ActivityThread {
             }
         }
 
-        if (DEBUG_CONFIGURATION) {
-            Slog.v(TAG, "Config callback " + cb + ": shouldChangeConfig=" + shouldChangeConfig);
-        }
-
         if (shouldChangeConfig) {
+            // Propagate the configuration change to the Activity and ResourcesManager.
+
+            // ContextThemeWrappers may override the configuration for that context.
+            // We must check and apply any overrides defined.
+            Configuration contextThemeWrapperOverrideConfig = null;
+            if (cb instanceof ContextThemeWrapper) {
+                final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+                contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
+            }
+
+            // We only update an Activity's configuration if this is not a global
+            // configuration change. This must also be done before the callback,
+            // or else we violate the contract that the new resources are available
+            // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
             if (activityToken != null) {
-                // We only update an Activity's configuration if this is not a global
-                // configuration change. This must also be done before the callback,
-                // or else we violate the contract that the new resources are available
-                // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
-                mResourcesManager.updateResourcesForActivity(activityToken, overrideConfig);
+                // Apply the ContextThemeWrapper override if necessary.
+                // NOTE: Make sure the configurations are not modified, as they are treated
+                // as immutable in many places.
+                final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
+                        amOverrideConfig, contextThemeWrapperOverrideConfig);
+                mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig);
             }
 
             if (reportToActivity) {
-                Configuration configToReport = newConfig;
-
-                if (cb instanceof ContextThemeWrapper) {
-                    // ContextThemeWrappers may override the configuration for that context.
-                    // We must check and apply any overrides defined.
-                    ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
-                    final Configuration localOverrideConfig =
-                            contextThemeWrapper.getOverrideConfiguration();
-                    if (localOverrideConfig != null) {
-                        configToReport = new Configuration(newConfig);
-                        configToReport.updateFrom(localOverrideConfig);
-                    }
-                }
-
+                // Apply the ContextThemeWrapper override if necessary.
+                // NOTE: Make sure the configurations are not modified, as they are treated
+                // as immutable in many places.
+                final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
+                        newConfig, contextThemeWrapperOverrideConfig);
                 cb.onConfigurationChanged(configToReport);
             }
 
index 152f45e..0b62ed2 100644 (file)
@@ -1191,14 +1191,18 @@ public final class LoadedApk {
 
         public void performReceive(Intent intent, int resultCode, String data,
                 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-            if (ActivityThread.DEBUG_BROADCAST) {
-                int seq = intent.getIntExtra("seq", -1);
-                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
-                        + " to " + mReceiver);
-            }
-            Args args = new Args(intent, resultCode, data, extras, ordered,
+            final Args args = new Args(intent, resultCode, data, extras, ordered,
                     sticky, sendingUser);
-            if (!mActivityThread.post(args)) {
+            if (intent == null) {
+                Log.wtf(TAG, "Null intent received");
+            } else {
+                if (ActivityThread.DEBUG_BROADCAST) {
+                    int seq = intent.getIntExtra("seq", -1);
+                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+                            + " seq=" + seq + " to " + mReceiver);
+                }
+            }
+            if (intent == null || !mActivityThread.post(args)) {
                 if (mRegistered && ordered) {
                     IActivityManager mgr = ActivityManagerNative.getDefault();
                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
index 18f93cd..7f467f0 100644 (file)
@@ -1576,8 +1576,11 @@ public class WallpaperManager {
         final String whichProp;
         final int defaultResId;
         if (which == FLAG_LOCK) {
+            /* Factory-default lock wallpapers are not yet supported
             whichProp = PROP_LOCK_WALLPAPER;
             defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
+            */
+            return null;
         } else {
             whichProp = PROP_WALLPAPER;
             defaultResId = com.android.internal.R.drawable.default_wallpaper;
index 5743b4d..0cee114 100644 (file)
@@ -1610,41 +1610,6 @@ public class CameraDeviceImpl extends CameraDevice
     }
 
     public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
-        //
-        // Constants below need to be kept up-to-date with
-        // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
-        //
-
-        //
-        // Error codes for onCameraError
-        //
-
-        /**
-         * Camera has been disconnected
-         */
-        public static final int ERROR_CAMERA_DISCONNECTED = 0;
-        /**
-         * Camera has encountered a device-level error
-         * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
-         */
-        public static final int ERROR_CAMERA_DEVICE = 1;
-        /**
-         * Camera has encountered a service-level error
-         * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
-         */
-        public static final int ERROR_CAMERA_SERVICE = 2;
-        /**
-         * Camera has encountered an error processing a single request.
-         */
-        public static final int ERROR_CAMERA_REQUEST = 3;
-        /**
-         * Camera has encountered an error producing metadata for a single capture
-         */
-        public static final int ERROR_CAMERA_RESULT = 4;
-        /**
-         * Camera has encountered an error producing an image buffer for a single capture
-         */
-        public static final int ERROR_CAMERA_BUFFER = 5;
 
         @Override
         public IBinder asBinder() {
@@ -1675,11 +1640,14 @@ public class CameraDeviceImpl extends CameraDevice
                     case ERROR_CAMERA_DEVICE:
                     case ERROR_CAMERA_SERVICE:
                         mInError = true;
+                        final int publicErrorCode = (errorCode == ERROR_CAMERA_DEVICE) ?
+                                StateCallback.ERROR_CAMERA_DEVICE :
+                                StateCallback.ERROR_CAMERA_SERVICE;
                         Runnable r = new Runnable() {
                             @Override
                             public void run() {
                                 if (!CameraDeviceImpl.this.isClosed()) {
-                                    mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
+                                    mDeviceCallback.onError(CameraDeviceImpl.this, publicErrorCode);
                                 }
                             }
                         };
@@ -2050,7 +2018,7 @@ public class CameraDeviceImpl extends CameraDevice
             public void run() {
                 if (!isClosed()) {
                     mDeviceCallback.onError(CameraDeviceImpl.this,
-                            CameraDeviceCallbacks.ERROR_CAMERA_SERVICE);
+                            StateCallback.ERROR_CAMERA_SERVICE);
                 }
             }
         };
index ba821e4..1565087 100644 (file)
@@ -37,7 +37,9 @@ public class MarshalRegistry {
      * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
      */
     public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
-        sRegisteredMarshalQueryables.add(queryable);
+        synchronized(sMarshalLock) {
+            sRegisteredMarshalQueryables.add(queryable);
+        }
     }
 
     /**
@@ -54,47 +56,50 @@ public class MarshalRegistry {
      */
     @SuppressWarnings("unchecked")
     public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
-        // TODO: can avoid making a new token each time by code-genning
-        // the list of type tokens and native types from the keys (at the call sites)
-        MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
-
-        /*
-         * Marshalers are instantiated lazily once they are looked up; successive lookups
-         * will not instantiate new marshalers.
-         */
-        Marshaler<T> marshaler =
-                (Marshaler<T>) sMarshalerMap.get(marshalToken);
-
-        if (sRegisteredMarshalQueryables.size() == 0) {
-            throw new AssertionError("No available query marshalers registered");
-        }
+        synchronized(sMarshalLock) {
+            // TODO: can avoid making a new token each time by code-genning
+            // the list of type tokens and native types from the keys (at the call sites)
+            MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
+
+            /*
+             * Marshalers are instantiated lazily once they are looked up; successive lookups
+             * will not instantiate new marshalers.
+             */
+            Marshaler<T> marshaler =
+                    (Marshaler<T>) sMarshalerMap.get(marshalToken);
+
+            if (marshaler == null) {
+
+                if (sRegisteredMarshalQueryables.size() == 0) {
+                    throw new AssertionError("No available query marshalers registered");
+                }
 
-        if (marshaler == null) {
-            // Query each marshaler to see if they support the native/managed type combination
-            for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
+                // Query each marshaler to see if they support the native/managed type combination
+                for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
 
-                MarshalQueryable<T> castedPotential =
-                        (MarshalQueryable<T>)potentialMarshaler;
+                    MarshalQueryable<T> castedPotential =
+                            (MarshalQueryable<T>)potentialMarshaler;
 
-                if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
-                    marshaler = castedPotential.createMarshaler(typeToken, nativeType);
-                    break;
+                    if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
+                        marshaler = castedPotential.createMarshaler(typeToken, nativeType);
+                        break;
+                    }
                 }
-            }
 
-            if (marshaler == null) {
-                throw new UnsupportedOperationException(
+                if (marshaler == null) {
+                    throw new UnsupportedOperationException(
                         "Could not find marshaler that matches the requested " +
-                                "combination of type reference " +
-                                typeToken + " and native type " +
-                                MarshalHelpers.toStringNativeType(nativeType));
+                        "combination of type reference " +
+                        typeToken + " and native type " +
+                        MarshalHelpers.toStringNativeType(nativeType));
+                }
+
+                // Only put when no cached version exists to avoid +0.5ms lookup per call.
+                sMarshalerMap.put(marshalToken, marshaler);
             }
 
-            // Only put when no cached version exists to avoid +0.5ms lookup per call.
-            sMarshalerMap.put(marshalToken, marshaler);
+            return marshaler;
         }
-
-        return marshaler;
     }
 
     private static class MarshalToken<T> {
@@ -125,9 +130,12 @@ public class MarshalRegistry {
         }
     }
 
-    private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
+    // Control access to the static data structures below
+    private static final Object sMarshalLock = new Object();
+
+    private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
             new ArrayList<MarshalQueryable<?>>();
-    private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
+    private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
             new HashMap<MarshalToken<?>, Marshaler<?>>();
 
     private MarshalRegistry() {
index ea5ae32..f4bf3ea 100644 (file)
@@ -176,7 +176,7 @@ public abstract class BatteryStats implements Parcelable {
     /**
      * Current version of checkin data format.
      */
-    static final String CHECKIN_VERSION = "17";
+    static final String CHECKIN_VERSION = "18";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -2371,6 +2371,20 @@ public abstract class BatteryStats implements Parcelable {
     };
 
     /**
+     * Return the counter keeping track of the amount of battery discharge while the screen was off,
+     * measured in micro-Ampere-hours. This will be non-zero only if the device's battery has
+     * a coulomb counter.
+     */
+    public abstract LongCounter getDischargeScreenOffCoulombCounter();
+
+    /**
+     * Return the counter keeping track of the amount of battery discharge measured in
+     * micro-Ampere-hours. This will be non-zero only if the device's battery has
+     * a coulomb counter.
+     */
+    public abstract LongCounter getDischargeCoulombCounter();
+
+    /**
      * Return the array of discharge step durations.
      */
     public abstract LevelStepTracker getDischargeLevelStepTracker();
@@ -2805,6 +2819,9 @@ public abstract class BatteryStats implements Parcelable {
                 rawRealtime, which);
         final int connChanges = getNumConnectivityChange(which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
+        final long dischargeCount = getDischargeCoulombCounter().getCountLocked(which);
+        final long dischargeScreenOffCount = getDischargeScreenOffCoulombCounter()
+                .getCountLocked(which);
 
         final StringBuilder sb = new StringBuilder(128);
         
@@ -2820,6 +2837,7 @@ public abstract class BatteryStats implements Parcelable {
                 totalRealtime / 1000, totalUptime / 1000,
                 getStartClockTime(),
                 whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000);
+
         
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
@@ -2969,12 +2987,14 @@ public abstract class BatteryStats implements Parcelable {
             dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
                     getDischargeStartLevel()-getDischargeCurrentLevel(),
                     getDischargeStartLevel()-getDischargeCurrentLevel(),
-                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
+                    dischargeCount / 1000, dischargeScreenOffCount / 1000);
         } else {
             dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
                     getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
                     getDischargeAmountScreenOnSinceCharge(),
-                    getDischargeAmountScreenOffSinceCharge());
+                    getDischargeAmountScreenOffSinceCharge(),
+                    dischargeCount / 1000, dischargeScreenOffCount / 1000);
         }
         
         if (reqUid < 0) {
@@ -3371,6 +3391,39 @@ public abstract class BatteryStats implements Parcelable {
                     formatTimeMs(sb, chargeTimeRemaining / 1000);
             pw.println(sb.toString());
         }
+
+        final LongCounter dischargeCounter = getDischargeCoulombCounter();
+        final long dischargeCount = dischargeCounter.getCountLocked(which);
+        if (dischargeCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
+        final LongCounter dischargeScreenOffCounter = getDischargeScreenOffCoulombCounter();
+        final long dischargeScreenOffCount = dischargeScreenOffCounter.getCountLocked(which);
+        if (dischargeScreenOffCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Screen off discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeScreenOffCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
+        final long dischargeScreenOnCount = dischargeCount - dischargeScreenOffCount;
+        if (dischargeScreenOnCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Screen on discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeScreenOnCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
         pw.print("  Start clock time: ");
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
 
index 6c21398..7ff01da 100644 (file)
@@ -695,6 +695,7 @@ public class RecoverySystem {
             String line = null;
             int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
             int timeTotal = -1;
+            int sourceVersion = -1;
             while ((line = in.readLine()) != null) {
                 // Here is an example of lines in last_install:
                 // ...
@@ -729,6 +730,8 @@ public class RecoverySystem {
 
                 if (line.startsWith("time")) {
                     timeTotal = scaled;
+                } else if (line.startsWith("source_version")) {
+                    sourceVersion = scaled;
                 } else if (line.startsWith("bytes_written")) {
                     bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
                             bytesWrittenInMiB + scaled;
@@ -742,6 +745,9 @@ public class RecoverySystem {
             if (timeTotal != -1) {
                 MetricsLogger.histogram(context, "ota_time_total", timeTotal);
             }
+            if (sourceVersion != -1) {
+                MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
+            }
             if (bytesWrittenInMiB != -1) {
                 MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
             }
index b4131b4..415e70c 100644 (file)
@@ -51,6 +51,7 @@ public class SurfaceControl {
 
     private static native void nativeSetLayer(long nativeObject, int zorder);
     private static native void nativeSetPosition(long nativeObject, float x, float y);
+    private static native void nativeSetPositionAppliesWithResize(long nativeObject);
     private static native void nativeSetSize(long nativeObject, int w, int h);
     private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
     private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -407,6 +408,16 @@ public class SurfaceControl {
         nativeSetPosition(mNativeObject, x, y);
     }
 
+    /**
+     * If the size changes in this transaction, position updates specified
+     * in this transaction will not complete until a buffer of the new size
+     * arrives.
+     */
+    public void setPositionAppliesWithResize() {
+        checkNotReleased();
+        nativeSetPositionAppliesWithResize(mNativeObject);
+    }
+
     public void setSize(int w, int h) {
         checkNotReleased();
         nativeSetSize(mNativeObject, w, h);
index 4742818..19b1cf3 100644 (file)
@@ -1938,7 +1938,7 @@ public final class ViewRootImpl implements ViewParent,
                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
                 mSurfaceHolder.mSurfaceLock.unlock();
                 if (mSurface.isValid()) {
-                    if (!hadSurface || surfaceGenerationId != mSurface.getGenerationId()) {
+                    if (!hadSurface) {
                         mSurfaceHolder.ungetCallbacks();
 
                         mIsCreating = true;
@@ -1951,7 +1951,7 @@ public final class ViewRootImpl implements ViewParent,
                         }
                         surfaceChanged = true;
                     }
-                    if (surfaceChanged) {
+                    if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
                                 lp.format, mWidth, mHeight);
                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
index d0d4507..52f35de 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.view.accessibility;
 
+import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -101,8 +102,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
     /**
      * Gets the title of the window.
      *
-     * @return The title.
+     * @return The title of the window, or {@code null} if none is available.
      */
+    @Nullable
     public CharSequence getTitle() {
         return mTitle;
     }
index 8b02352..07d38d7 100644 (file)
@@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats {
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 144 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 146 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -509,6 +509,9 @@ public class BatteryStatsImpl extends BatteryStats {
     int mDischargeAmountScreenOff;
     int mDischargeAmountScreenOffSinceCharge;
 
+    private LongSamplingCounter mDischargeScreenOffCounter;
+    private LongSamplingCounter mDischargeCounter;
+
     static final int MAX_LEVEL_STEPS = 200;
 
     int mInitStepMode = 0;
@@ -565,6 +568,16 @@ public class BatteryStatsImpl extends BatteryStats {
         return mWakeupReasonStats;
     }
 
+    @Override
+    public LongCounter getDischargeScreenOffCoulombCounter() {
+        return mDischargeScreenOffCounter;
+    }
+
+    @Override
+    public LongCounter getDischargeCoulombCounter() {
+        return mDischargeCounter;
+    }
+
     public BatteryStatsImpl() {
         this(new SystemClocks());
     }
@@ -912,7 +925,6 @@ public class BatteryStatsImpl extends BatteryStats {
         final TimeBase mTimeBase;
         long mCount;
         long mLoadedCount;
-        long mLastCount;
         long mUnpluggedCount;
         long mPluggedCount;
 
@@ -921,7 +933,6 @@ public class BatteryStatsImpl extends BatteryStats {
             mPluggedCount = in.readLong();
             mCount = mPluggedCount;
             mLoadedCount = in.readLong();
-            mLastCount = 0;
             mUnpluggedCount = in.readLong();
             timeBase.add(this);
         }
@@ -949,20 +960,19 @@ public class BatteryStatsImpl extends BatteryStats {
         }
 
         public long getCountLocked(int which) {
-            long val = mCount;
+            long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
             if (which == STATS_SINCE_UNPLUGGED) {
                 val -= mUnpluggedCount;
             } else if (which != STATS_SINCE_CHARGED) {
                 val -= mLoadedCount;
             }
-
             return val;
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount
-                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+                    + " mLoadedCount=" + mLoadedCount
                     + " mUnpluggedCount=" + mUnpluggedCount
                     + " mPluggedCount=" + mPluggedCount);
         }
@@ -976,7 +986,7 @@ public class BatteryStatsImpl extends BatteryStats {
          */
         void reset(boolean detachIfReset) {
             mCount = 0;
-            mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
+            mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
                 detach();
             }
@@ -993,7 +1003,6 @@ public class BatteryStatsImpl extends BatteryStats {
         void readSummaryFromParcelLocked(Parcel in) {
             mLoadedCount = in.readLong();
             mCount = mLoadedCount;
-            mLastCount = 0;
             mUnpluggedCount = mPluggedCount = mLoadedCount;
         }
     }
@@ -7566,6 +7575,8 @@ public class BatteryStatsImpl extends BatteryStats {
         mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
         mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+        mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
+        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
         long uptime = mClocks.uptimeMillis() * 1000;
         long realtime = mClocks.elapsedRealtime() * 1000;
@@ -8123,6 +8134,8 @@ public class BatteryStatsImpl extends BatteryStats {
         mDischargeAmountScreenOffSinceCharge = 0;
         mDischargeStepTracker.init();
         mChargeStepTracker.init();
+        mDischargeScreenOffCounter.reset(false);
+        mDischargeCounter.reset(false);
     }
 
     public void resetAllStatsCmdLocked() {
@@ -9327,6 +9340,7 @@ public class BatteryStatsImpl extends BatteryStats {
             mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
             mHistoryCur.batteryStatus = (byte)status;
             mHistoryCur.batteryLevel = (byte)level;
+            mHistoryCur.batteryChargeUAh = chargeUAh;
             mMaxChargeStepLevel = mMinDischargeStepLevel =
                     mLastChargeStepLevel = mLastDischargeStepLevel = level;
             mLastChargingStateLevel = level;
@@ -9358,6 +9372,12 @@ public class BatteryStatsImpl extends BatteryStats {
             mHistoryCur.batteryPlugType = (byte)plugType;
             mHistoryCur.batteryTemperature = (short)temp;
             mHistoryCur.batteryVoltage = (char)volt;
+            if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+                // Only record discharges
+                final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+                mDischargeCounter.addCountLocked(chargeDiff);
+                mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+            }
             mHistoryCur.batteryChargeUAh = chargeUAh;
             setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
         } else {
@@ -9394,6 +9414,12 @@ public class BatteryStatsImpl extends BatteryStats {
             }
             if (chargeUAh >= (mHistoryCur.batteryChargeUAh+10)
                     || chargeUAh <= (mHistoryCur.batteryChargeUAh-10)) {
+                if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+                    // Only record discharges
+                    final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+                    mDischargeCounter.addCountLocked(chargeDiff);
+                    mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+                }
                 mHistoryCur.batteryChargeUAh = chargeUAh;
                 changed = true;
             }
@@ -10075,6 +10101,8 @@ public class BatteryStatsImpl extends BatteryStats {
         mChargeStepTracker.readFromParcel(in);
         mDailyDischargeStepTracker.readFromParcel(in);
         mDailyChargeStepTracker.readFromParcel(in);
+        mDischargeCounter.readSummaryFromParcelLocked(in);
+        mDischargeScreenOffCounter.readSummaryFromParcelLocked(in);
         int NPKG = in.readInt();
         if (NPKG > 0) {
             mDailyPackageChanges = new ArrayList<>(NPKG);
@@ -10425,6 +10453,8 @@ public class BatteryStatsImpl extends BatteryStats {
         mChargeStepTracker.writeToParcel(out);
         mDailyDischargeStepTracker.writeToParcel(out);
         mDailyChargeStepTracker.writeToParcel(out);
+        mDischargeCounter.writeSummaryFromParcelLocked(out);
+        mDischargeScreenOffCounter.writeSummaryFromParcelLocked(out);
         if (mDailyPackageChanges != null) {
             final int NPKG = mDailyPackageChanges.size();
             out.writeInt(NPKG);
@@ -10880,6 +10910,8 @@ public class BatteryStatsImpl extends BatteryStats {
         mDischargeAmountScreenOffSinceCharge = in.readInt();
         mDischargeStepTracker.readFromParcel(in);
         mChargeStepTracker.readFromParcel(in);
+        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mLastWriteTime = in.readLong();
 
         mKernelWakelockStats.clear();
@@ -11028,6 +11060,8 @@ public class BatteryStatsImpl extends BatteryStats {
         out.writeInt(mDischargeAmountScreenOffSinceCharge);
         mDischargeStepTracker.writeToParcel(out);
         mChargeStepTracker.writeToParcel(out);
+        mDischargeCounter.writeToParcel(out);
+        mDischargeScreenOffCounter.writeToParcel(out);
         out.writeLong(mLastWriteTime);
 
         if (inclUids) {
index 7e38d9b..3cf7a4e 100644 (file)
@@ -1550,7 +1550,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
     private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
         endOnGoingFadeAnimation();
         cleanupPrimaryActionMode();
-        if (mPrimaryActionModeView == null) {
+        // We want to create new mPrimaryActionModeView in two cases: if there is no existing
+        // instance at all, or if there is one, but it is detached from window. The latter case
+        // might happen when app is resized in multi-window mode and decor view is preserved
+        // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause
+        // app memory leaks because killMode() is called when the dismiss animation ends and from
+        // cleanupPrimaryActionMode() invocation above.
+        if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) {
             if (mWindow.isFloating()) {
                 // Use the action bar theme.
                 final TypedValue outValue = new TypedValue();
@@ -1616,6 +1622,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                 ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub);
                 if (stub != null) {
                     mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
+                    mPrimaryActionModePopup = null;
                 }
             }
         }
@@ -2278,9 +2285,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                 }
                 if (mPrimaryActionModeView != null) {
                     endOnGoingFadeAnimation();
+                    // Store action mode view reference, so we can access it safely when animation
+                    // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView,
+                    // so no need to store reference to it in separate variable.
+                    final ActionBarContextView lastActionModeView = mPrimaryActionModeView;
                     mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
                             1f, 0f);
                     mFadeAnim.addListener(new Animator.AnimatorListener() {
+
                                 @Override
                                 public void onAnimationStart(Animator animation) {
 
@@ -2288,12 +2300,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
 
                                 @Override
                                 public void onAnimationEnd(Animator animation) {
-                                    mPrimaryActionModeView.setVisibility(GONE);
-                                    if (mPrimaryActionModePopup != null) {
-                                        mPrimaryActionModePopup.dismiss();
+                                    // If mPrimaryActionModeView has changed - it means that we've
+                                    // cleared the content while preserving decor view. We don't
+                                    // want to change the state of new instances accidentally here.
+                                    if (lastActionModeView == mPrimaryActionModeView) {
+                                        lastActionModeView.setVisibility(GONE);
+                                        if (mPrimaryActionModePopup != null) {
+                                            mPrimaryActionModePopup.dismiss();
+                                        }
+                                        lastActionModeView.killMode();
+                                        mFadeAnim = null;
                                     }
-                                    mPrimaryActionModeView.removeAllViews();
-                                    mFadeAnim = null;
                                 }
 
                                 @Override
index 18408aa..9ad750d 100644 (file)
@@ -528,16 +528,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
 
     @Override
     public void setTitle(CharSequence title) {
+        setTitle(title, true);
+    }
+
+    public void setTitle(CharSequence title, boolean updateAccessibilityTitle) {
         if (mTitleView != null) {
             mTitleView.setText(title);
         } else if (mDecorContentParent != null) {
             mDecorContentParent.setWindowTitle(title);
         }
         mTitle = title;
-        WindowManager.LayoutParams params = getAttributes();
-        if (!TextUtils.equals(title, params.accessibilityTitle)) {
-            params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
-            dispatchWindowAttributesChanged(getAttributes());
+        if (updateAccessibilityTitle) {
+            WindowManager.LayoutParams params = getAttributes();
+            if (!TextUtils.equals(title, params.accessibilityTitle)) {
+                params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
+                dispatchWindowAttributesChanged(getAttributes());
+            }
         }
     }
 
index a9ed9dc..ff75677 100644 (file)
@@ -248,6 +248,15 @@ static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfl
     }
 }
 
+static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
+        jlong nativeObject) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    status_t err = ctrl->setPositionAppliesWithResize();
+    if (err < 0 && err != NO_INIT) {
+        doThrowIAE(env);
+    }
+}
+
 static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     status_t err = ctrl->setSize(w, h);
@@ -658,6 +667,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
             (void*)nativeSetLayer },
     {"nativeSetPosition", "(JFF)V",
             (void*)nativeSetPosition },
+    {"nativeSetPositionAppliesWithResize", "(J)V",
+            (void*)nativeSetPositionAppliesWithResize },
     {"nativeSetSize", "(JII)V",
             (void*)nativeSetSize },
     {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
index b03ba20..2ef1fcf 100644 (file)
     <!-- Added in N -->
     <protected-broadcast android:name="android.intent.action.ANR" />
     <protected-broadcast android:name="android.intent.action.CALL" />
+    <protected-broadcast android:name="android.intent.action.CALL_PRIVILEGED" />
     <protected-broadcast android:name="android.intent.action.DROPBOX_ENTRY_ADDED" />
     <protected-broadcast android:name="android.intent.action.INPUT_METHOD_CHANGED" />
     <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
     <permission android:name="android.permission.MANAGE_USERS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows an application to create, remove users and get the list of
+         users on the device. Applications holding this permission can only create restricted,
+         guest, managed, and ephemeral users. For creating other kind of users,
+         {@link android.Manifest.permission#MANAGE_USERS} is needed.
+         This permission is not available to third party applications. -->
+    <permission android:name="android.permission.CREATE_USERS"
+        android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to set the profile owners and the device owner.
          This permission is not available to third party applications.-->
     <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
index aa84ed0..17712b0 100644 (file)
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"indi"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>dəq</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>dəq</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>d</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>saat</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>saat</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>st</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>st</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>gün</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>gün</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>g</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>g</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>il</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>il</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>i</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>i</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>dəqiqədə</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>dəqiqədə</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>d-də</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>d-də</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>saata</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>saata</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>s-da</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>s-da</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>gündə</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>gündə</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>g-də</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>g-də</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ildə</item>
index 92541f2..616d2b8 100644 (file)
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"jetzt"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> T.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> T.</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> J.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> J.</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
       <item quantity="other">in <xliff:g id="COUNT_1">%d</xliff:g> min</item>
       <item quantity="one">in <xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other">in <xliff:g id="COUNT_1">%d</xliff:g> d</item>
-      <item quantity="one">in <xliff:g id="COUNT_0">%d</xliff:g> d</item>
+      <item quantity="other">in <xliff:g id="COUNT_1">%d</xliff:g> T.</item>
+      <item quantity="one">in <xliff:g id="COUNT_0">%d</xliff:g> T.</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other">in <xliff:g id="COUNT_1">%d</xliff:g> a</item>
-      <item quantity="one">in <xliff:g id="COUNT_0">%d</xliff:g> a</item>
+      <item quantity="other">in <xliff:g id="COUNT_1">%d</xliff:g> J.</item>
+      <item quantity="one">in <xliff:g id="COUNT_0">%d</xliff:g> J.</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other">vor <xliff:g id="COUNT_1">%d</xliff:g> Minuten</item>
index 393b8ff..2f76a33 100644 (file)
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> días</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> día</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> años</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> año</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
       <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> min</item>
       <item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> días</item>
-      <item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> día</item>
+      <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
       <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> años</item>
index 0626546..fcccc55 100644 (file)
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"agora"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> min</item>
+      <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one">en <xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
       <item quantity="other">en <xliff:g id="COUNT_1">%d</xliff:g> h</item>
index 993cd7e..ee89493 100644 (file)
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"Բ"</string>
-    <string name="kilobyteShort" msgid="5973789783504771878">"ԿԲ"</string>
+    <string name="kilobyteShort" msgid="5973789783504771878">"կԲ"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"ՄԲ"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"ԳԲ"</string>
     <string name="terabyteShort" msgid="231613018159186962">"ՏԲ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Փոփոխել"</string>
     <string name="whichSendApplication" msgid="6902512414057341668">"Կիսվել"</string>
-    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Տարածել ըստ %1$s"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Կիսվել %1$s-ի միջոցով"</string>
     <string name="whichSendApplicationLabel" msgid="4579076294675975354">"Տրամադրել"</string>
     <string name="whichSendToApplication" msgid="8272422260066642057">"Ուղարկել այս հավելվածով"</string>
     <string name="whichSendToApplicationNamed" msgid="7768387871529295325">"Ուղարկել %1$s հավելվածով"</string>
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածի աշխատանքը շարունակաբար ընդհատվում է"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> գործընթացը շարունակաբար ընդհատվում է"</string>
     <string name="aerr_restart" msgid="7581308074153624475">"Կրկին բացել հավելվածը"</string>
-    <string name="aerr_report" msgid="5371800241488400617">"Ուղարկել կարծիք"</string>
+    <string name="aerr_report" msgid="5371800241488400617">"Կարծիք հայտնել"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Փակել"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Անջատել ձայնը մինչև սարքի վերագործարկումը"</string>
     <string name="aerr_wait" msgid="3199956902437040261">"Սպասել"</string>
index ee3c606..860ff12 100644 (file)
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"åpne bilder, medieinnhold og filer på enheten din"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"spill inn lyd"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ta opp lyd"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"ta bilder og ta opp video"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
index 12f2ba7..d9156b5 100644 (file)
     <string name="user_owner_label" msgid="1119010402169916617">"ਨਿੱਜੀ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="managed_profile_label" msgid="5289992269827577857">"ਕੰਮ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"ਸੰਪਰਕ"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"à¨\86ਪਣà©\87 à¨¸à©°à¨ªà¨°à¨\95ਾà¨\82 à¨¨à©\82à©° à¨\90à¨\95ਸà©\88ਸ à¨\95ਰà©\8b"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"à¨\86ਪਣà©\87 à¨¸à©°à¨ªà¨°à¨\95ਾà¨\82 à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9a à¨\95ਰਨ"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ਟਿਕਾਣਾ"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"à¨\87ਸ à¨¡à©\80ਵਾà¨\88ਸ à¨¦à©\87 à¨¨à¨¿à¨°à¨§à¨¾à¨°à¨¿à¨¤ à¨¸à¨¥à¨¾à¨¨ à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9aà©\8b"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"à¨\87ਸ à¨¡à©\80ਵਾà¨\88ਸ à¨¦à©\87 à¨\9fਿà¨\95ਾਣà©\87 à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9a à¨\95ਰਨ"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"ਕੈਲੰਡਰ"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"à¨\86ਪਣà©\87 à¨\95à©\88ਲੰਡਰ à¨¦à©\80 à¨\90à¨\95ਸà©\88ਸ à¨\95ਰà©\8b"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"ਤà©\81ਹਾਡà©\87 à¨\95à©\88ਲੰਡਰ à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9a à¨\95ਰਨ"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS à¨¸à©\81ਨà©\87ਹà©\87 à¨­à©\87à¨\9cà©\8b à¨\85ਤà©\87 à¨¦à¨¿à¨\96ਾà¨\93"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS à¨¸à©\81ਨà©\87ਹà©\87 à¨­à©\87à¨\9cਣ à¨\85ਤà©\87 à¨¦à©\87à¨\96ਣ"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ਸਟੋਰੇਜ"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"ਆਪਣੀ ਡੀਵਾਈਸ ’ਤੇ ਫੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣ"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"ਆਪਣੀ ਡੀਵਾਈਸ ’ਤੇ ਫੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"ਮਾਈਕ੍ਰੋਫੋਨ"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"à¨\94ਡà©\80à¨\93 à¨°à¨¿à¨\95ਾਰਡ à¨\95ਰà©\8b"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"à¨\94ਡà©\80à¨\93 à¨°à¨¿à¨\95ਾਰਡ à¨\95ਰਨ"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"ਕੈਮਰਾ"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"ਤਸਵà©\80ਰਾà¨\82 à¨\96ਿੱà¨\9aà©\8b à¨\85ਤà©\87 à¨µà©\80ਡà©\80à¨\93 à¨°à¨¿à¨\95ਾਰਡ à¨\95ਰà©\8b"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"ਤਸਵà©\80ਰਾà¨\82 à¨²à©\88ਣ à¨\85ਤà©\87 à¨µà©\80ਡà©\80à¨\93 à¨°à¨¿à¨\95ਾਰਡ à¨\95ਰਨ"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"ਫੋਨ"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"ਫ਼à©\8bਨ à¨\95ਾਲਾà¨\82 à¨\95ਰà©\8b à¨\85ਤà©\87 à¨\89ਹਨਾà¨\82 à¨¨à©\82à©° à¨ªà©\8dਰਬੰਧਿਤ à¨\95ਰà©\8b"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"ਫ਼à©\8bਨ à¨\95ਾਲਾà¨\82 à¨\95ਰਨ à¨\85ਤà©\87 à¨\89ਹਨਾà¨\82 à¨¦à¨¾ à¨ªà©\8dਰਬੰਧਨ à¨\95ਰਨ"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"ਸਰੀਰ ਸੰਵੇਦਕ"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"à¨\86ਪਣà©\87 à¨®à¨¹à©±à¨¤à¨µà¨ªà©\82ਰਣ à¨²à©±à¨\9bਣਾà¨\82 à¨¬à¨¾à¨°à©\87 à¨¸à©°à¨µà©\87ਦà¨\95 à¨¡à©\88à¨\9fਾ à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9a"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"à¨\86ਪਣà©\87 à¨¸à¨°à©\80ਰ à¨¦à©\87 à¨\85ਹਿਮ à¨\9aਿੰਨà©\8dਹਾà¨\82 à¨¬à¨¾à¨°à©\87 à¨¸à©°à¨µà©\87ਦà¨\95 à¨¡à©\88à¨\9fà©\87 à¨¤à©±à¨\95 à¨ªà¨¹à©\81à©°à¨\9a à¨\95ਰਨ"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ਵਿੰਡੋ ਸਮੱਗਰੀ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"ਇੱਕ ਵਿੰਡੋ ਦੀ ਸਮੱਗਰੀ ਦੀ ਜਾਂਚ ਕਰੋ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਇੰਟਰੈਕਟ ਕਰ ਰਹੇ ਹੋ।"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"ਐਕਸਪਲੋਰ ਬਾਇ ਟਚ ਚਾਲੂ ਕਰੋ"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਵੱਲੋਂ ਪ੍ਰਾਪਤ ਕੀਤੇ ਸੈਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹੇ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਸੈਲ ਪ੍ਰਸਾਰਨ ਚਿਤਾਵਨੀਆਂ ਤੁਹਾਨੂੰ ਐਮਰਜੈਂਸੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਨਿਰਧਾਰਿਤ ਸਥਾਨਾਂ ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੇ ਪ੍ਰਦਰਸ਼ਨ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੇ ਹਨ ਜਦੋਂ ਇੱਕ ਐਮਰਜੈਂਸੀ ਸੈਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ਸਬਸਕ੍ਰਾਈਬ ਕੀਤੇ ਫੀਡਸ ਪੜ੍ਹੋ"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"ਐਪ ਨੂੰ ਵਰਤਮਾਨ ਵਿੱਚ ਸਿੰਕ ਕੀਤੇ ਫੀਡਸ ਬਾਰੇ ਵੇਰਵੇ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"SMS à¨¸à©\81ਨà©\87ਹà©\87 à¨­à©\87à¨\9cà©\8b à¨\85ਤà©\87 à¨¦à¨¿à¨\96ਾà¨\93"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"SMS à¨¸à©\81ਨà©\87ਹà©\87 à¨­à©\87à¨\9cਣ à¨\85ਤà©\87 à¨¦à©\87à¨\96ਣ"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"ਐਪ ਨੂੰ SMS ਸੁਨੇਹੇ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਪੈ ਸਕਦੇ ਹਨ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜ ਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"ਤੁਹਾਡੇ ਟੈਕਸਟ ਸੁਨੇਹੇ (SMS ਜਾਂ MMS) ਪੜ੍ਹੋ"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਟੈਬਲੇਟ ਜਾਂ SIM ਕਾਰਡ ਤੇ ਸਟੋਰ ਕੀਤੇ SMS ਸੁਨੇਹੇ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਸਾਰੇ SMS ਸੁਨੇਹੇ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਸਮੱਗਰੀ ਜਾਂ ਗੁਪਤਤਾ ਤੇ ਧਿਆਨ ਦਿੱਤੇ ਬਿਨਾਂ।"</string>
index aecda44..998eea5 100644 (file)
@@ -174,6 +174,7 @@ please see themes_device_defaults.xml.
 
         <!-- Window attributes -->
         <item name="windowBackground">@drawable/screen_background_selector_dark</item>
+        <item name="windowBackgroundFallback">?attr/colorBackground</item>
         <item name="windowClipToOutline">false</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
index 1335790..4d93c83 100644 (file)
@@ -677,7 +677,7 @@ a bitmap drawable that's 48x48 pixels for medium-density screens, all the differ
   <li>48x48 (1.0x baseline) for medium-density</li>
   <li>72x72 (1.5x) for high-density</li>
   <li>96x96 (2.0x) for extra-high-density</li>
-  <li>180x180 (3.0x) for extra-extra-high-density</li>
+  <li>144x144 (3.0x) for extra-extra-high-density</li>
   <li>192x192 (4.0x) for extra-extra-extra-high-density (launcher icon only; see
     <a href="#xxxhdpi-note">note</a> above)</li>
 </ul>
index d9616d9..584bef8 100755 (executable)
@@ -619,7 +619,7 @@ package provides APIs to support adding and managing custom tabs in your apps. <
 <a href="{@docRoot}reference/android/support/customtabs/CustomTabsService.html">Custom Tabs
 Service</a>
 and
-<a href="{@docRoot}reference/android/support/customtabs/CustomTabsSCallback.html">Custom Tabs
+<a href="{@docRoot}reference/android/support/customtabs/CustomTabsCallback.html">Custom Tabs
 Callback</a>.  </p>
 
 
index 8b23f73..941f5c3 100644 (file)
@@ -523,7 +523,7 @@ onView(withId(R.id.changeTextBt)).perform(click());</pre>
 mDevice = UiDevice.getInstance(getInstrumentation());
 
 // Perform a short press on the HOME button
-mDevice().pressHome();
+mDevice.pressHome();
 
 // Bring up the default launcher by searching for
 // a UI component that matches the content-description for the launcher button
index cc963c6..cf564d0 100644 (file)
@@ -68,7 +68,7 @@ These steps describe how to set up a {@link android.support.v7.widget.Toolbar}
 as your activity's app bar:
 
 <ol>
-  <li>Add the the
+  <li>Add the
   <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
   appcompat</a> support library to your project, as described in <a href=
   "{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
index 8592c0f..0c0ab7f 100644 (file)
@@ -437,15 +437,25 @@ Number Slow draw: 23342
 </p>
 
 <ul>
-  <li>Rendering Performance 101
+  <li>
+    <a class="external-link" href="https://www.youtube.com/watch?v=HXQhu6qfTVU">
+      Rendering Performance 101</a>
   </li>
-  <li>Why 60fps?
+  <li>
+    <a class="external-link" href="https://www.youtube.com/watch?v=CaMTIgxCSqU">
+      Why 60fps?</a>
   </li>
-  <li>Android UI and the GPU
+  <li>
+    <a class="external-link" href="https://www.youtube.com/watch?v=WH9AFhgwmDw">
+      Android, UI, and the GPU</a>
   </li>
-  <li>Invalidations Layouts and performance
+  <li>
+    <a class="external-link" href="https://www.youtube.com/watch?v=we6poP0kw6E">
+      Invalidations, Layouts, and Performance</a>
   </li>
-  <li>Analyzing UI Performance with Systrace
+  <li>
+    <a href="{@docRoot}studio/profile/systrace.html">
+      Analyzing UI Performance with Systrace</a>
   </li>
 </ul>
 
index faf6a52..c9d4af6 100644 (file)
@@ -256,6 +256,7 @@ LOCAL_SRC_FILES += \
     tests/unit/MatrixTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
     tests/unit/RenderNodeTests.cpp \
+    tests/unit/RenderPropertiesTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/SnapshotTests.cpp \
     tests/unit/StringUtilsTests.cpp \
index ea2e15b..6db345a 100644 (file)
@@ -66,8 +66,13 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
             offscreenBuffer->texture.id(), 0);
     GL_CHECKPOINT(LOW);
 
-    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
-            "framebuffer incomplete!");
+    int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
+            "framebuffer incomplete, status %d, textureId %d, size %dx%d",
+            status,
+            offscreenBuffer->texture.id(),
+            offscreenBuffer->texture.width(),
+            offscreenBuffer->texture.height());
 
     // Change the viewport & ortho projection
     setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
index cb8e55f..b8a5ce6 100644 (file)
@@ -86,7 +86,9 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
             ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
                     layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
 
-            const Rect& layerDamage = layers.entries()[i].damage;
+            Rect layerDamage = layers.entries()[i].damage;
+            // TODO: ensure layer damage can't be larger than layer
+            layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight);
             layerNode->computeOrdering();
 
             // map current light center into RenderNode's coordinate space
index 6e848fd..be2dab9 100644 (file)
@@ -319,6 +319,8 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
         transformUpdateNeeded = true;
     } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
 #if HWUI_NEW_OPS
+        // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+        // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
         RenderState& renderState = mLayer->renderState;
         if (properties().fitsOnLayer()) {
             mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
index 3952798..696cc29 100644 (file)
@@ -611,7 +611,9 @@ public:
     bool fitsOnLayer() const {
         const DeviceInfo* deviceInfo = DeviceInfo::get();
         return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
-                        && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+                        && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize()
+                        && mPrimitiveFields.mWidth > 0
+                        && mPrimitiveFields.mHeight > 0;
     }
 
     bool promotedToLayer() const {
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
new file mode 100644 (file)
index 0000000..9001098
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RenderProperties.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderProperties, layerValidity) {
+    DeviceInfo::initialize();
+
+    const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
+    ASSERT_LE(2048, maxTextureSize);
+    ASSERT_GT(100000, maxTextureSize);
+
+    RenderProperties props;
+
+    // simple cases that all should fit on layers
+    props.setLeftTopRightBottom(0, 0, 100, 100);
+    ASSERT_TRUE(props.fitsOnLayer());
+    props.setLeftTopRightBottom(100, 2000, 300, 4000);
+    ASSERT_TRUE(props.fitsOnLayer());
+    props.setLeftTopRightBottom(-10, -10, 510, 512);
+    ASSERT_TRUE(props.fitsOnLayer());
+
+    // Too big - can't have layer bigger than max texture size
+    props.setLeftTopRightBottom(0, 0, maxTextureSize + 1, maxTextureSize + 1);
+    ASSERT_FALSE(props.fitsOnLayer());
+
+    // Too small - can't have 0 dimen layer
+    props.setLeftTopRightBottom(0, 0, 100, 0);
+    ASSERT_FALSE(props.fitsOnLayer());
+}
index b0e5e4e..6588ee1 100644 (file)
@@ -20,6 +20,7 @@ import static android.os.Environment.isStandardDirectory;
 import static android.os.Environment.STANDARD_DIRECTORIES;
 import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
 import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
+
 import static com.android.documentsui.LocalPreferences.getScopedAccessPermissionStatus;
 import static com.android.documentsui.LocalPreferences.PERMISSION_ASK;
 import static com.android.documentsui.LocalPreferences.PERMISSION_ASK_AGAIN;
@@ -201,14 +202,23 @@ public class OpenExternalDirectoryActivity extends Activity {
         final List<VolumeInfo> volumes = sm.getVolumes();
         if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
         File internalRoot = null;
+        boolean found = true;
         for (VolumeInfo volume : volumes) {
             if (isRightVolume(volume, root, userId)) {
+                found = true;
                 internalRoot = volume.getInternalPathForUser(userId);
                 // Must convert path before calling getDocIdForFileCreateNewDir()
                 if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
                 file = isRoot ? internalRoot : new File(internalRoot, directory);
+                volumeUuid = storageVolume.getUuid();
                 volumeLabel = sm.getBestVolumeDescription(volume);
-                volumeUuid = volume.getFsUuid();
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = storageVolume.getDescription(activity);
+                }
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = activity.getString(android.R.string.unknownName);
+                    Log.w(TAG, "No volume description  for " + volume + "; using " + volumeLabel);
+                }
                 break;
             }
         }
@@ -229,7 +239,7 @@ public class OpenExternalDirectoryActivity extends Activity {
             return true;
         }
 
-        if (volumeLabel == null) {
+        if (!found) {
             Log.e(TAG, "Could not get volume for " + file);
             logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
@@ -277,15 +287,16 @@ public class OpenExternalDirectoryActivity extends Activity {
     private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
         final File userPath = volume.getPathForUser(userId);
         final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
-        final boolean isVisible = volume.isVisibleForWrite(userId);
+        final boolean isMounted = volume.isMountedReadable();
         if (DEBUG)
-            Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
-                    + " volumePath: " + volume.getPath().getPath()
-                    + " pathForUser: " + path
-                    + " internalPathForUser: " + volume.getInternalPath()
-                    + " isVisible: " + isVisible);
-
-        return volume.isVisibleForWrite(userId) && root.equals(path);
+            Log.d(TAG, "Volume: " + volume
+                    + "\n\tuserId: " + userId
+                    + "\n\tuserPath: " + userPath
+                    + "\n\troot: " + root
+                    + "\n\tpath: " + path
+                    + "\n\tisMounted: " + isMounted);
+
+        return isMounted && root.equals(path);
     }
 
     private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
@@ -455,7 +466,7 @@ public class OpenExternalDirectoryActivity extends Activity {
                 message = TextUtils.expandTemplate(
                         getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
                                 : R.string.open_external_dialog_request),
-                        mAppLabel, directory, mVolumeLabel);
+                                mAppLabel, directory, mVolumeLabel);
             }
             final TextView messageField = (TextView) view.findViewById(R.id.message);
             messageField.setText(message);
index 348fcac..b6c45b7 100644 (file)
@@ -26,6 +26,6 @@
     <string name="plugin_vendor_samsung">Samsung</string>
     <string name="plugin_vendor_epson">Epson</string>
     <string name="plugin_vendor_konica_minolta">Konica Minolta</string>
-    <string name="plugin_vendor_fuji">Fuji</string>
+    <string name="plugin_vendor_fuji_xerox">Fuji Xerox</string>
     <string name="plugin_vendor_morpia">Mopria</string>
 </resources>
index 52889ce..703cf6f 100644 (file)
@@ -60,7 +60,7 @@
     </vendor>
 
     <vendor>
-        <name>@string/plugin_vendor_fuji</name>
+        <name>@string/plugin_vendor_fuji_xerox</name>
         <package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
         <mdns-names>
             <mdns-name>FUJI XEROX</mdns-name>
index 7a2d0d8..b0da08b 100755 (executable)
@@ -39,8 +39,10 @@ class MDnsUtils {
         String usbMfg = getString(attributes.get(ATTRIBUTE__USB_MFG));
         String usbMdl = getString(attributes.get(ATTRIBUTE__USB_MDL));
         String mfg = getString(attributes.get(ATTRIBUTE__MFG));
-        return containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) || containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues) && !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) || containsString(usbMdl, EXCLUDE_FUJI));
-
+        return (containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) ||
+                containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues)) &&
+                !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) ||
+                        containsString(usbMdl, EXCLUDE_FUJI));
     }
 
     public static String getVendor(NsdServiceInfo networkDevice) {
index be3df54..c318275 100644 (file)
@@ -614,6 +614,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+
+        mMediaSizeComparator.onConfigurationChanged(newConfig);
+
         if (mPrintPreviewController != null) {
             mPrintPreviewController.onOrientationChanged();
         }
index 912ee1d..7289301 100644 (file)
 
 package com.android.printspooler.util;
 
+import android.annotation.NonNull;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.print.PrintAttributes.MediaSize;
-import android.util.ArrayMap;
 
 import com.android.printspooler.R;
 
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -30,7 +33,10 @@ import java.util.Map;
  */
 public final class MediaSizeUtils {
 
-    private static Map<MediaSize, String> sMediaSizeToStandardMap;
+    private static Map<MediaSize, Integer> sMediaSizeToStandardMap;
+
+    /** The media size standard for all media sizes no standard is defined for */
+    private static int sMediaSizeStandardIso;
 
     private MediaSizeUtils() {
         /* do nothing - hide constructor */
@@ -47,22 +53,32 @@ public final class MediaSizeUtils {
         return MediaSize.getStandardMediaSizeById(mediaSizeId);
     }
 
-    private static String getStandardForMediaSize(Context context, MediaSize mediaSize) {
+    /**
+     * Get the standard the {@link MediaSize} belongs to.
+     *
+     * @param context   The context of the caller
+     * @param mediaSize The {@link MediaSize} to be resolved
+     *
+     * @return The standard the {@link MediaSize} belongs to
+     */
+    private static int getStandardForMediaSize(Context context, MediaSize mediaSize) {
         if (sMediaSizeToStandardMap == null) {
-            sMediaSizeToStandardMap = new ArrayMap<MediaSize, String>();
+            sMediaSizeStandardIso = Integer.parseInt(context.getString(
+                    R.string.mediasize_standard_iso));
+
+            sMediaSizeToStandardMap = new HashMap<>();
             String[] mediaSizeToStandardMapValues = context.getResources()
                     .getStringArray(R.array.mediasize_to_standard_map);
             final int mediaSizeToStandardCount = mediaSizeToStandardMapValues.length;
             for (int i = 0; i < mediaSizeToStandardCount; i += 2) {
                 String mediaSizeId = mediaSizeToStandardMapValues[i];
                 MediaSize key = MediaSize.getStandardMediaSizeById(mediaSizeId);
-                String value = mediaSizeToStandardMapValues[i + 1];
+                int value = Integer.parseInt(mediaSizeToStandardMapValues[i + 1]);
                 sMediaSizeToStandardMap.put(key, value);
             }
         }
-        String standard = sMediaSizeToStandardMap.get(mediaSize);
-        return (standard != null) ? standard : context.getString(
-                R.string.mediasize_standard_iso);
+        Integer standard = sMediaSizeToStandardMap.get(mediaSize);
+        return (standard != null) ? standard : sMediaSizeStandardIso;
     }
 
     /**
@@ -73,32 +89,76 @@ public final class MediaSizeUtils {
     public static final class MediaSizeComparator implements Comparator<MediaSize> {
         private final Context mContext;
 
+        /** Current configuration */
+        private Configuration mCurrentConfig;
+
+        /** The standard to use for the current locale */
+        private int mCurrentStandard;
+
+        /** Mapping from media size to label */
+        private final @NonNull Map<MediaSize, String> mMediaSizeToLabel;
+
         public MediaSizeComparator(Context context) {
             mContext = context;
+            mMediaSizeToLabel = new HashMap<>();
+            mCurrentStandard = Integer.parseInt(mContext.getString(R.string.mediasize_standard));
+        }
+
+        /**
+         * Handle a configuration change by reloading all resources.
+         *
+         * @param newConfig The new configuration that will be applied.
+         */
+        public void onConfigurationChanged(@NonNull Configuration newConfig) {
+            if (mCurrentConfig == null ||
+                    (newConfig.diff(mCurrentConfig) & ActivityInfo.CONFIG_LOCALE) != 0) {
+                mCurrentStandard = Integer
+                        .parseInt(mContext.getString(R.string.mediasize_standard));
+                mMediaSizeToLabel.clear();
+
+                mCurrentConfig = newConfig;
+            }
+        }
+
+        /**
+         * Get the label for a {@link MediaSize}.
+         *
+         * @param context   The context the label should be loaded for
+         * @param mediaSize The {@link MediaSize} to resolve
+         *
+         * @return The label for the media size
+         */
+        public @NonNull String getLabel(@NonNull Context context, @NonNull MediaSize mediaSize) {
+            String label = mMediaSizeToLabel.get(mediaSize);
+
+            if (label == null) {
+                label = mediaSize.getLabel(context.getPackageManager());
+                mMediaSizeToLabel.put(mediaSize, label);
+            }
+
+            return label;
         }
 
         @Override
         public int compare(MediaSize lhs, MediaSize rhs) {
-            String currentStandard = mContext.getString(R.string.mediasize_standard);
-            String lhsStandard = getStandardForMediaSize(mContext, lhs);
-            String rhsStandard = getStandardForMediaSize(mContext, rhs);
+            int lhsStandard = getStandardForMediaSize(mContext, lhs);
+            int rhsStandard = getStandardForMediaSize(mContext, rhs);
 
             // The current standard always wins.
-            if (lhsStandard.equals(currentStandard)) {
-                if (!rhsStandard.equals(currentStandard)) {
+            if (lhsStandard == mCurrentStandard) {
+                if (rhsStandard != mCurrentStandard) {
                     return -1;
                 }
-            } else if (rhsStandard.equals(currentStandard)) {
+            } else if (rhsStandard == mCurrentStandard) {
                 return 1;
             }
 
-            if (!lhsStandard.equals(rhsStandard)) {
+            if (lhsStandard != rhsStandard) {
                 // Different standards - use the standard ordering.
-                return lhsStandard.compareTo(rhsStandard);
+                return Integer.valueOf(lhsStandard).compareTo(rhsStandard);
             } else {
                 // Same standard - sort alphabetically by label.
-                return lhs.getLabel(mContext.getPackageManager()).
-                        compareTo(rhs.getLabel(mContext.getPackageManager()));
+                return getLabel(mContext, lhs).compareTo(getLabel(mContext, rhs));
             }
         }
     }
index 08dbb01..2cd6813 100644 (file)
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Scale ng transition animation"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Scale ng tagal ng animator"</string>
     <string name="overlay_display_devices_title" msgid="5364176287998398539">"I-simulate, ika-2 display"</string>
-    <string name="debug_applications_category" msgid="4206913653849771549">"Apps"</string>
+    <string name="debug_applications_category" msgid="4206913653849771549">"Mga App"</string>
     <string name="immediately_destroy_activities" msgid="1579659389568133959">"Huwag magtago ng mga aktibidad"</string>
     <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Sirain ang bawat aktibidad sa sandaling iwan ito ng user"</string>
     <string name="app_process_limit_title" msgid="4280600650253107163">"Limitasyon ng proseso sa background"</string>
index 9c0aa35..2efefb3 100644 (file)
@@ -90,7 +90,7 @@
     <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.CREATE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
index cf96457..71bd798 100644 (file)
@@ -109,18 +109,18 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
         if (mListening) {
             if (mPosition != position) {
                 // Clear out the last pages from listening.
-                mPages.get(mPosition).setListening(false);
+                setPageListening(mPosition, false);
                 if (mOffPage) {
-                    mPages.get(mPosition + 1).setListening(false);
+                    setPageListening(mPosition + 1, false);
                 }
                 // Set the new pages to listening
-                mPages.get(position).setListening(true);
+                setPageListening(position, true);
                 if (offPage) {
-                    mPages.get(position + 1).setListening(true);
+                    setPageListening(position + 1, true);
                 }
             } else if (mOffPage != offPage) {
                 // Whether we are showing position + 1 has changed.
-                mPages.get(mPosition + 1).setListening(offPage);
+                setPageListening(mPosition + 1, offPage);
             }
         }
         // Save the current state.
@@ -128,6 +128,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
         mOffPage = offPage;
     }
 
+    private void setPageListening(int position, boolean listening) {
+        if (position >= mPages.size()) return;
+        mPages.get(position).setListening(listening);
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         return false;
index 8d6e17e..d5fb8f2 100644 (file)
@@ -178,6 +178,7 @@ public class QSContainer extends FrameLayout {
     private void updateQsState() {
         boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
         mQSPanel.setExpanded(mQsExpanded);
+        mQSDetail.setExpanded(mQsExpanded);
         mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
                 ? View.VISIBLE
                 : View.INVISIBLE);
index 0cf7e47..a40e5b7 100644 (file)
@@ -31,6 +31,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 import android.widget.TextView;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
@@ -64,6 +65,9 @@ public class QSDetail extends LinearLayout {
     private boolean mFullyExpanded;
     private View mQsDetailHeaderBack;
     private BaseStatusBarHeader mHeader;
+    private boolean mTriggeredExpand;
+    private int mOpenX;
+    private int mOpenY;
 
     public QSDetail(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -112,6 +116,7 @@ public class QSDetail extends LinearLayout {
     public void setQsPanel(QSPanel panel, BaseStatusBarHeader header) {
         mQsPanel = panel;
         mHeader = header;
+        mHeader.setCallback(mQsPanelCallback);
         mQsPanel.setCallback(mQsPanelCallback);
     }
 
@@ -126,6 +131,12 @@ public class QSDetail extends LinearLayout {
         mFullyExpanded = fullyExpanded;
     }
 
+    public void setExpanded(boolean qsExpanded) {
+        if (!qsExpanded) {
+            mTriggeredExpand = false;
+        }
+    }
+
     private void updateDetailText() {
         mDetailDoneButton.setText(R.string.quick_settings_done);
         mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
@@ -161,6 +172,22 @@ public class QSDetail extends LinearLayout {
                     }
                 });
             }
+            if (!mFullyExpanded) {
+                mTriggeredExpand = true;
+                mHost.animateToggleQSExpansion();
+            } else {
+                mTriggeredExpand = false;
+            }
+            mOpenX = x;
+            mOpenY = y;
+        } else {
+            // Ensure we collapse into the same point we opened from.
+            x = mOpenX;
+            y = mOpenY;
+            if (mTriggeredExpand) {
+                mHost.animateToggleQSExpansion();
+                mTriggeredExpand = false;
+            }
         }
 
         boolean visibleDiff = (mDetailAdapter != null) != (adapter != null);
index 6945176..2c874e5 100644 (file)
@@ -23,6 +23,7 @@ import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -56,7 +57,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
 
     private int mPanelPaddingBottom;
     private int mBrightnessPaddingTop;
-    private boolean mExpanded;
+    protected boolean mExpanded;
     protected boolean mListening;
 
     private Callback mCallback;
@@ -70,7 +71,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
 
     private QSCustomizer mCustomizePanel;
     private Record mDetailRecord;
-    private boolean mTriggeredExpand;
 
     public QSPanel(Context context) {
         this(context, null);
@@ -221,7 +221,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
         }
         MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
         if (!mExpanded) {
-            mTriggeredExpand = false;
             closeDetail();
         } else {
             logTiles();
@@ -279,6 +278,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
     public void setTiles(Collection<QSTile<?>> tiles, boolean collapsedView) {
         for (TileRecord record : mRecords) {
             mTileLayout.removeTile(record);
+            record.tile.removeCallback(record.callback);
         }
         mRecords.clear();
         for (QSTile<?> tile : tiles) {
@@ -294,6 +294,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
         return new QSTileView(mContext, tile.createTileView(mContext), collapsedView);
     }
 
+    protected boolean shouldShowDetail() {
+        return mExpanded;
+    }
+
     protected void addTile(final QSTile<?> tile, boolean collapsedView) {
         final TileRecord r = new TileRecord();
         r.tile = tile;
@@ -306,7 +310,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
 
             @Override
             public void onShowDetail(boolean show) {
-                QSPanel.this.showDetail(show, r);
+                // Both the collapsed and full QS panels get this callback, this check determines
+                // which one should handle showing the detail.
+                if (shouldShowDetail()) {
+                    QSPanel.this.showDetail(show, r);
+                }
             }
 
             @Override
@@ -330,6 +338,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
             }
         };
         r.tile.addCallback(callback);
+        r.callback = callback;
         final View.OnClickListener click = new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -390,17 +399,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
     }
 
     protected void handleShowDetail(Record r, boolean show) {
-        if (show) {
-            if (!mExpanded) {
-                mTriggeredExpand = true;
-                mHost.animateToggleQSExpansion();
-            } else {
-                mTriggeredExpand = false;
-            }
-        } else if (mTriggeredExpand) {
-            mHost.animateToggleQSExpansion();
-            mTriggeredExpand = false;
-        }
         if (r instanceof TileRecord) {
             handleShowDetailTile((TileRecord) r, show);
         } else {
@@ -520,6 +518,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
         public QSTile<?> tile;
         public QSTileBaseView tileView;
         public boolean scanState;
+        public QSTile.Callback callback;
     }
 
     public interface Callback {
index 8d9f23f..974de08 100644 (file)
@@ -161,6 +161,10 @@ public abstract class QSTile<TState extends State> {
         mHandler.obtainMessage(H.ADD_CALLBACK, callback).sendToTarget();
     }
 
+    public void removeCallback(Callback callback) {
+        mHandler.obtainMessage(H.REMOVE_CALLBACK, callback).sendToTarget();
+    }
+
     public void removeCallbacks() {
         mHandler.sendEmptyMessage(H.REMOVE_CALLBACKS);
     }
@@ -224,6 +228,10 @@ public abstract class QSTile<TState extends State> {
         handleRefreshState(null);
     }
 
+    private void handleRemoveCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
     private void handleRemoveCallbacks() {
         mCallbacks.clear();
     }
@@ -334,7 +342,8 @@ public abstract class QSTile<TState extends State> {
         private static final int DESTROY = 10;
         private static final int CLEAR_STATE = 11;
         private static final int REMOVE_CALLBACKS = 12;
-        private static final int SET_LISTENING = 13;
+        private static final int REMOVE_CALLBACK = 13;
+        private static final int SET_LISTENING = 14;
 
         private H(Looper looper) {
             super(looper);
@@ -350,6 +359,9 @@ public abstract class QSTile<TState extends State> {
                 } else if (msg.what == REMOVE_CALLBACKS) {
                     name = "handleRemoveCallbacks";
                     handleRemoveCallbacks();
+                } else if (msg.what == REMOVE_CALLBACK) {
+                    name = "handleRemoveCallback";
+                    handleRemoveCallback((QSTile.Callback) msg.obj);
                 } else if (msg.what == CLICK) {
                     name = "handleClick";
                     if (mState.disabledByPolicy) {
index b28d0f2..c984abe 100644 (file)
@@ -77,6 +77,11 @@ public class QuickQSPanel extends QSPanel {
     }
 
     @Override
+    protected boolean shouldShowDetail() {
+        return !mExpanded;
+    }
+
+    @Override
     protected void drawTile(TileRecord r, State state) {
         if (state instanceof SignalState) {
             State copy = r.tile.newTileState();
@@ -90,11 +95,6 @@ public class QuickQSPanel extends QSPanel {
     }
 
     @Override
-    protected void showDetail(boolean show, Record r) {
-        // Do nothing, will be handled by the QSPanel.
-    }
-
-    @Override
     protected QSTileBaseView createTileView(QSTile<?> tile, boolean collapsedView) {
         return new QSTileBaseView(mContext, tile.createTileView(mContext), collapsedView);
     }
index 72a589f..e757560 100644 (file)
@@ -56,6 +56,7 @@ public class TaskCardView extends LinearLayout {
     private ImageView mBadgeView;
     private Task mTask;
     private boolean mDismissState;
+    private boolean mTouchExplorationEnabled;
     private int mCornerRadius;
 
     private ViewFocusAnimator mViewFocusAnimator;
@@ -90,7 +91,8 @@ public class TaskCardView extends LinearLayout {
                 R.dimen.recents_task_view_rounded_corners_radius);
         mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, mInfoFieldView);
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (!ssp.isTouchExplorationEnabled()) {
+        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+        if (!mTouchExplorationEnabled) {
             mDismissIconView.setVisibility(VISIBLE);
         } else {
             mDismissIconView.setVisibility(GONE);
@@ -237,10 +239,15 @@ public class TaskCardView extends LinearLayout {
     private void setDismissState(boolean dismissState) {
         if (mDismissState != dismissState) {
             mDismissState = dismissState;
-            if (dismissState) {
-                mDismissAnimationsHolder.startEnterAnimation();
-            } else {
-                mDismissAnimationsHolder.startExitAnimation();
+            // Check for touch exploration to ensure dismiss icon/text do not
+            // get animated. This should be removed based on decision from
+            // b/29208918
+            if (!mTouchExplorationEnabled) {
+                if (dismissState) {
+                    mDismissAnimationsHolder.startEnterAnimation();
+                } else {
+                    mDismissAnimationsHolder.startExitAnimation();
+                }
             }
         }
     }
index 6e1c862..79eef43 100644 (file)
@@ -20,6 +20,7 @@ import android.content.Context;
 import android.util.AttributeSet;
 import android.widget.RelativeLayout;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSPanel.Callback;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -44,4 +45,5 @@ public abstract class BaseStatusBarHeader extends RelativeLayout implements
     public abstract void setBatteryController(BatteryController batteryController);
     public abstract void setNextAlarmController(NextAlarmController nextAlarmController);
     public abstract void setUserInfoController(UserInfoController userInfoController);
+    public abstract void setCallback(Callback qsPanelCallback);
 }
index 8360544..e091d6d 100644 (file)
@@ -38,6 +38,7 @@ import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSAnimator;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSPanel.Callback;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -222,6 +223,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     @Override
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
+        mHeaderQsPanel.setExpanded(expanded);
         updateEverything();
     }
 
@@ -393,6 +395,11 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     }
 
     @Override
+    public void setCallback(Callback qsPanelCallback) {
+        mHeaderQsPanel.setCallback(qsPanelCallback);
+    }
+
+    @Override
     public void setEmergencyCallsOnly(boolean show) {
         boolean changed = show != mShowEmergencyCallsOnly;
         if (changed) {
index a051973..72eafd8 100644 (file)
@@ -44,6 +44,7 @@ import com.android.systemui.BatteryMeterView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSPanel.Callback;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DetailAdapter;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -511,6 +512,10 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
     }
 
     @Override
+    public void setCallback(Callback qsPanelCallback) {
+    }
+
+    @Override
     public void onClick(View v) {
         if (v == mSettingsButton) {
             if (mSettingsButton.isTunerClick()) {
index acc2ec3..334b228 100644 (file)
@@ -9849,7 +9849,11 @@ if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soF
 
         synchronized(this) {
             if (mActiveRestoreSession != null) {
-                Slog.d(TAG, "Restore session requested but one already active");
+                Slog.i(TAG, "Restore session requested but one already active");
+                return null;
+            }
+            if (mBackupRunning) {
+                Slog.i(TAG, "Restore session requested but currently running backups");
                 return null;
             }
             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
index 3eadb5c..9154b8e 100644 (file)
@@ -222,7 +222,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
                             } catch (RemoteException e) {
                                 Slog.e(TAG,"Unable to call onBrEdrDown", e);
                             } finally {
-                                mBluetoothLock.readLock().lock();
+                                mBluetoothLock.readLock().unlock();
                             }
                         } else if (st == BluetoothAdapter.STATE_ON){
                             // disable without persisting the setting
index e0b4960..36ec2eb 100644 (file)
@@ -1431,6 +1431,13 @@ public class LocationManagerService extends ILocationManager.Stub {
                 for (UpdateRecord record : records) {
                     if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
+
+                        // Don't assign battery blame for update records whose
+                        // client has no permission to receive location data.
+                        if (!providerRequest.locationRequests.contains(locationRequest)) {
+                            continue;
+                        }
+
                         if (locationRequest.getInterval() <= thresholdInterval) {
                             if (record.mReceiver.mWorkSource != null
                                     && record.mReceiver.mWorkSource.size() > 0
index c89b6ea..9c75a00 100644 (file)
@@ -3031,7 +3031,8 @@ class MountService extends IMountService.Stub
                 if (forWrite) {
                     match = vol.isVisibleForWrite(userId);
                 } else {
-                    match = vol.isVisibleForRead(userId) || includeInvisible;
+                    match = vol.isVisibleForRead(userId)
+                            || (includeInvisible && vol.getPath() != null);
                 }
                 if (!match) continue;
 
index 2d6b5ef..3fd78fd 100644 (file)
@@ -6036,7 +6036,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (appId < 0 && packageName != null) {
             try {
                 appId = UserHandle.getAppId(AppGlobals.getPackageManager()
-                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
+                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
             } catch (RemoteException e) {
             }
         }
@@ -13881,7 +13881,12 @@ public final class ActivityManagerService extends ActivityManagerNative
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+                    if (dumpCheckinFormat) {
+                        dumpBroadcastStatsCheckinLocked(fd, pw, args, opti, dumpCheckin,
+                                dumpPackage);
+                    } else {
+                        dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+                    }
                 }
             } else if ("intents".equals(cmd) || "i".equals(cmd)) {
                 String[] newArgs;
index 0e4c9a4..52c002d 100644 (file)
@@ -1097,21 +1097,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
             // Don't debug things in the system process
             if (!aInfo.processName.equals("system")) {
                 if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
-                    final ProcessRecord app = mService.getProcessRecordLocked(
-                            aInfo.processName, aInfo.applicationInfo.uid, true);
-                    // If the process already started, we can't wait for debugger and shouldn't
-                    // modify the debug settings.
-                    // For non-persistent debug, normally we set the debug app here, and restores
-                    // to the original at attachApplication time. However, if the app process
-                    // already exists, we won't get another attachApplication, and the debug setting
-                    // never gets restored. Furthermore, if we get two such calls back-to-back,
-                    // both mOrigDebugApp and mDebugApp will become the same app, and it won't be
-                    // cleared even if we get attachApplication after the app process is killed.
-                    if (app == null || app.thread == null) {
-                        mService.setDebugApp(aInfo.processName, true, false);
-                    } else {
-                        Slog.w(TAG, "Ignoring waitForDebugger because process already exists");
-                    }
+                    mService.setDebugApp(aInfo.processName, true, false);
                 }
 
                 if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
index 61b1317..522e42b 100644 (file)
@@ -166,8 +166,9 @@ class ActivityStarter {
     private Intent mNewTaskIntent;
     private ActivityStack mSourceStack;
     private ActivityStack mTargetStack;
-    // TODO: Is the mMoveHome flag really needed?
-    private boolean mMovedHome;
+    // Indicates that we moved other task and are going to put something on top soon, so
+    // we don't want to show it redundantly or accidentally change what's shown below.
+    private boolean mMovedOtherTask;
     private boolean mMovedToFront;
     private boolean mNoAnimation;
     private boolean mKeepCurTransition;
@@ -204,7 +205,7 @@ class ActivityStarter {
         mSourceStack = null;
 
         mTargetStack = null;
-        mMovedHome = false;
+        mMovedOtherTask = false;
         mMovedToFront = false;
         mNoAnimation = false;
         mKeepCurTransition = false;
@@ -1013,7 +1014,6 @@ class ActivityStarter {
                 resumeTargetStackIfNeeded();
                 return START_RETURN_INTENT_TO_CALLER;
             }
-
             setTaskFromIntentActivity(mReusedActivity);
 
             if (!mAddingToTask && mReuseTask == null) {
@@ -1082,7 +1082,7 @@ class ActivityStarter {
                 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
-            if (!mMovedHome) {
+            if (!mMovedOtherTask) {
                 updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
             }
         } else if (mSourceRecord != null) {
@@ -1443,7 +1443,7 @@ class ActivityStarter {
                 if (mLaunchTaskBehind && mSourceRecord != null) {
                     intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
                 }
-                mMovedHome = true;
+                mMovedOtherTask = true;
 
                 // If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities
                 // will be cleared soon by ActivityStarter in setTaskFromIntentActivity().
@@ -1521,6 +1521,10 @@ class ActivityStarter {
             mReuseTask = intentActivity.task;
             mReuseTask.performClearTaskLocked();
             mReuseTask.setIntent(mStartActivity);
+            // When we clear the task - focus will be adjusted, which will bring another task
+            // to top before we launch the activity we need. This will temporary swap their
+            // mTaskToReturnTo values and we don't want to overwrite them accidentally.
+            mMovedOtherTask = true;
         } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                 || mLaunchSingleInstance || mLaunchSingleTask) {
             ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
index 87141b4..1906da7 100644 (file)
@@ -16338,8 +16338,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                 for (int curUser : users) {
                     long timeout = SystemClock.uptimeMillis() + 5000;
                     synchronized (conn) {
-                        long now = SystemClock.uptimeMillis();
-                        while (conn.mContainerService == null && now < timeout) {
+                        long now;
+                        while (conn.mContainerService == null &&
+                                (now = SystemClock.uptimeMillis()) < timeout) {
                             try {
                                 conn.wait(timeout - now);
                             } catch (InterruptedException e) {
index b916790..e7518e7 100644 (file)
@@ -167,6 +167,12 @@ public class UserManagerService extends IUserManager.Stub {
     private static final String RESTRICTIONS_FILE_PREFIX = "res_";
     private static final String XML_SUFFIX = ".xml";
 
+    private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
+            UserInfo.FLAG_MANAGED_PROFILE
+            | UserInfo.FLAG_EPHEMERAL
+            | UserInfo.FLAG_RESTRICTED
+            | UserInfo.FLAG_GUEST;
+
     private static final int MIN_USER_ID = 10;
     // We need to keep process uid within Integer.MAX_VALUE.
     private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
@@ -465,7 +471,7 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
-        checkManageUsersPermission("query users");
+        checkManageOrCreateUsersPermission("query users");
         synchronized (mUsersLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             final int userSize = mUsers.size();
@@ -1407,6 +1413,41 @@ public class UserManagerService extends IUserManager.Stub {
     }
 
     /**
+     * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}
+     * can make certain calls to the UserManager.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller is not system or root
+     * @see #hasManageOrCreateUsersPermission()
+     */
+    private static final void checkManageOrCreateUsersPermission(String message) {
+        if (!hasManageOrCreateUsersPermission()) {
+            throw new SecurityException(
+                    "You either need MANAGE_USERS or CREATE_USERS permission to: " + message);
+        }
+    }
+
+    /**
+     * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
+     * to create user/profiles other than what is allowed for
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} permission, then it will only
+     * allow callers with {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} permission.
+     */
+    private static final void checkManageOrCreateUsersPermission(int creationFlags) {
+        if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
+            if (!hasManageOrCreateUsersPermission()) {
+                throw new SecurityException("You either need MANAGE_USERS or CREATE_USERS "
+                        + "permission to create an user with flags: " + creationFlags);
+            }
+        } else if (!hasManageUsersPermission()) {
+            throw new SecurityException("You need MANAGE_USERS permission to create an user "
+                    + " with flags: " + creationFlags);
+        }
+    }
+
+    /**
      * @return whether the calling UID is system UID or root's UID or the calling app has the
      * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
      */
@@ -1420,6 +1461,23 @@ public class UserManagerService extends IUserManager.Stub {
     }
 
     /**
+     * @return whether the calling UID is system UID or root's UID or the calling app has the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+     */
+    private static final boolean hasManageOrCreateUsersPermission() {
+        final int callingUid = Binder.getCallingUid();
+        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || callingUid == Process.ROOT_UID
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.CREATE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
      * Enforces that only the system UID or root's UID (on any user) can make certain calls to the
      * UserManager.
      *
@@ -2005,13 +2063,13 @@ public class UserManagerService extends IUserManager.Stub {
 
     @Override
     public UserInfo createProfileForUser(String name, int flags, int userId) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         return createUserInternal(name, flags, userId);
     }
 
     @Override
     public UserInfo createUser(String name, int flags) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
@@ -2255,7 +2313,7 @@ public class UserManagerService extends IUserManager.Stub {
      */
     @Override
     public boolean removeUser(int userHandle) {
-        checkManageUsersPermission("Only the system can remove users");
+        checkManageOrCreateUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
                 UserManager.DISALLOW_REMOVE_USER, false)) {
             Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
index 6987744..568f94c 100644 (file)
@@ -2589,8 +2589,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
             final PhoneWindow win = new PhoneWindow(context);
             win.setIsStartingWindow(true);
 
-            final Resources r = context.getResources();
-            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
+            CharSequence label = context.getResources().getText(labelRes, null);
+            // Only change the accessibility title if the label is localized
+            if (label != null) {
+                win.setTitle(label, true);
+            } else {
+                win.setTitle(nonLocalizedLabel, false);
+            }
 
             win.setType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
index 101f56f..8be5dfb 100644 (file)
@@ -1203,9 +1203,6 @@ final class AccessibilityController {
             window.layer = windowState.mLayer;
             window.token = windowState.mClient.asBinder();
             window.title = windowState.mAttrs.accessibilityTitle;
-            if (window.title == null) {
-                window.title = windowState.mAttrs.getTitle();
-            }
             window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
 
             WindowState attachedWindow = windowState.mAttachedWindow;
index e46ed8d..36d9697 100644 (file)
@@ -824,22 +824,11 @@ class WindowStateAnimator {
             mTmpSize.bottom = mTmpSize.top + 1;
         }
 
-        final int displayId = w.getDisplayId();
-        float scale = 1.0f;
-        // Magnification is supported only for the default display.
-        if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
-            final MagnificationSpec spec =
-                    mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w);
-            if (spec != null && !spec.isNop()) {
-                scale = spec.scale;
-            }
-        }
-
         // Adjust for surface insets.
-        mTmpSize.left -= scale * attrs.surfaceInsets.left;
-        mTmpSize.top -= scale * attrs.surfaceInsets.top;
-        mTmpSize.right += scale * attrs.surfaceInsets.right;
-        mTmpSize.bottom += scale * attrs.surfaceInsets.bottom;
+        mTmpSize.left -= attrs.surfaceInsets.left;
+        mTmpSize.top -= attrs.surfaceInsets.top;
+        mTmpSize.right += attrs.surfaceInsets.right;
+        mTmpSize.bottom += attrs.surfaceInsets.bottom;
     }
 
     boolean hasSurface() {
@@ -1300,9 +1289,13 @@ class WindowStateAnimator {
     void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
                 + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
-        if (!clipRect.equals(mLastClipRect)) {
-            mLastClipRect.set(clipRect);
-            mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+        if (clipRect != null) {
+            if (!clipRect.equals(mLastClipRect)) {
+                mLastClipRect.set(clipRect);
+                mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+            }
+        } else {
+            mSurfaceController.clearCropInTransaction(recoveringMemory);
         }
         if (!finalClipRect.equals(mLastFinalClipRect)) {
             mLastFinalClipRect.set(finalClipRect);
@@ -1314,7 +1307,6 @@ class WindowStateAnimator {
     }
 
     private int resolveStackClip() {
-
         // App animation overrides window animation stack clip mode.
         if (mAppAnimator != null && mAppAnimator.animation != null) {
             return mAppAnimator.getStackClip();
@@ -1420,6 +1412,9 @@ class WindowStateAnimator {
         // aren't observing known issues here outside of PiP resizing. (Typically
         // the other windows that use -1 are PopupWindows which aren't likely
         // to be rendering while we resize).
+
+        boolean wasForceScaled = mForceScaleUntilResize;
+
         if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) {
             mSurfaceResized = mSurfaceController.setSizeInTransaction(
                     mTmpSize.width(), mTmpSize.height(), recoveringMemory);
@@ -1428,13 +1423,17 @@ class WindowStateAnimator {
         }
         mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
 
-
         calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+
+        float surfaceWidth = mSurfaceController.getWidth();
+        float surfaceHeight = mSurfaceController.getHeight();
+
         if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
             int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
             int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
-            float surfaceWidth = mSurfaceController.getWidth();
-            float surfaceHeight = mSurfaceController.getHeight();
+            if (!mForceScaleUntilResize) {
+                mSurfaceController.forceScaleableInTransaction(true);
+            }
             // We want to calculate the scaling based on the content area, not based on
             // the entire surface, so that we scale in sync with windows that don't have insets.
             mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
@@ -1455,7 +1454,8 @@ class WindowStateAnimator {
             posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
             posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
 
-            mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+            mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
+                    (float)Math.floor(posY), recoveringMemory);
 
             // Since we are scaled to fit in our previously desired crop, we can now
             // expose the whole window in buffer space, and not risk extending
@@ -1467,7 +1467,7 @@ class WindowStateAnimator {
             // We need to ensure for each surface, that we disable transformation matrix
             // scaling in the same transaction which we resize the surface in.
             // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
-            // then take over the scaling until the new buffer arrives, and things 
+            // then take over the scaling until the new buffer arrives, and things
             // will be seamless.
             mForceScaleUntilResize = true;
         } else {
@@ -1475,7 +1475,25 @@ class WindowStateAnimator {
                     recoveringMemory);
         }
 
-        updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
+        // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
+        // to prevent further updates until buffer latch. Normally position
+        // would continue to apply immediately. But we need a different position
+        // before and after resize (since we have scaled the shadows, as discussed
+        // above).
+        if (wasForceScaled && !mForceScaleUntilResize) {
+            mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
+            mSurfaceController.forceScaleableInTransaction(false);
+        }
+
+        Rect clipRect = mTmpClipRect;
+        if (w.inPinnedWorkspace()) {
+            clipRect = null;
+            task.mStack.getDimBounds(mTmpFinalClipRect);
+            mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
+                    -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
+        }
+
+        updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
 
         mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
                 mDtDx * w.mVScale * mExtraVScale,
index 9646a49..fd0bb99 100644 (file)
@@ -26,6 +26,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static android.view.Surface.SCALING_MODE_FREEZE;
 import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
 
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -78,7 +79,15 @@ class WindowSurfaceController {
 
         title = name;
 
-        if (DEBUG_SURFACE_TRACE) {
+        // For opaque child windows placed under parent windows,
+        // we use a special SurfaceControl which mirrors commands
+        // to a black-out layer placed one Z-layer below the surface.
+        // This prevents holes to whatever app/wallpaper is underneath.
+        if (animator.mWin.isChildWindow() &&
+                animator.mWin.mSubLayer < 0) {
+            mSurfaceControl = new SurfaceControlWithBackground(s,
+                    name, w, h, format, flags);
+        } else if (DEBUG_SURFACE_TRACE) {
             mSurfaceControl = new SurfaceTrace(
                     s, name, w, h, format, flags);
         } else {
@@ -194,6 +203,20 @@ class WindowSurfaceController {
         }
     }
 
+    void clearCropInTransaction(boolean recoveringMemory) {
+        if (SHOW_TRANSACTIONS) logSurface(
+                "CLEAR CROP", null);
+        try {
+            Rect clipRect = new Rect(0, 0, -1, -1);
+            mSurfaceControl.setWindowCrop(clipRect);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error setting clearing crop of " + this, e);
+            if (!recoveringMemory) {
+                mAnimator.reclaimSomeSurfaceMemory("crop", true);
+            }
+        }
+    }
+
     void setFinalCropInTransaction(Rect clipRect) {
         if (SHOW_TRANSACTIONS) logSurface(
                 "FINAL CROP " + clipRect.toShortString(), null);
@@ -236,6 +259,10 @@ class WindowSurfaceController {
         }
     }
 
+    void setPositionAppliesWithResizeInTransaction(boolean recoveringMemory) {
+        mSurfaceControl.setPositionAppliesWithResize();
+    }
+
     void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
             boolean recoveringMemory) {
         try {
@@ -554,6 +581,13 @@ class WindowSurfaceController {
         }
 
         @Override
+        public void setPositionAppliesWithResize() {
+            if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPositionAppliesWithResize(): OLD: "
+                    + this + ". Called by" + Debug.getCallers(9));
+            super.setPositionAppliesWithResize();
+        }
+
+        @Override
         public void setSize(int w, int h) {
             if (w != mSize.x || h != mSize.y) {
                 if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:"
@@ -719,4 +753,125 @@ class WindowSurfaceController {
                     + " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")";
         }
     }
+
+    private static class SurfaceControlWithBackground extends SurfaceControl {
+        private SurfaceControl mBackgroundControl;
+        private boolean mOpaque = true;
+        private boolean mVisible = false;
+
+        public SurfaceControlWithBackground(SurfaceSession s,
+                       String name, int w, int h, int format, int flags)
+                   throws OutOfResourcesException {
+            super(s, name, w, h, format, flags);
+            mBackgroundControl = new SurfaceControl(s, name, w, h,
+                    PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
+            mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
+        }
+
+        @Override
+        public void setAlpha(float alpha) {
+            super.setAlpha(alpha);
+            mBackgroundControl.setAlpha(alpha);
+        }
+
+        @Override
+        public void setLayer(int zorder) {
+            super.setLayer(zorder);
+            mBackgroundControl.setLayer(zorder - 1);
+        }
+
+        @Override
+        public void setPosition(float x, float y) {
+            super.setPosition(x, y);
+            mBackgroundControl.setPosition(x, y);
+        }
+
+        @Override
+        public void setSize(int w, int h) {
+            super.setSize(w, h);
+            mBackgroundControl.setSize(w, h);
+        }
+
+        @Override
+        public void setWindowCrop(Rect crop) {
+            super.setWindowCrop(crop);
+            mBackgroundControl.setWindowCrop(crop);
+        }
+
+        @Override
+        public void setFinalCrop(Rect crop) {
+            super.setFinalCrop(crop);
+            mBackgroundControl.setFinalCrop(crop);
+        }
+
+        @Override
+        public void setLayerStack(int layerStack) {
+            super.setLayerStack(layerStack);
+            mBackgroundControl.setLayerStack(layerStack);
+        }
+
+        @Override
+        public void setOpaque(boolean isOpaque) {
+            super.setOpaque(isOpaque);
+            mOpaque = isOpaque;
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void setSecure(boolean isSecure) {
+            super.setSecure(isSecure);
+        }
+
+        @Override
+        public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+            super.setMatrix(dsdx, dtdx, dsdy, dtdy);
+            mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+        }
+
+        @Override
+        public void hide() {
+            mVisible = false;
+            super.hide();
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void show() {
+            mVisible = true;
+            super.show();
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void destroy() {
+            super.destroy();
+            mBackgroundControl.destroy();
+        }
+
+        @Override
+        public void release() {
+            super.release();
+            mBackgroundControl.release();
+        }
+
+        @Override
+        public void setTransparentRegionHint(Region region) {
+            super.setTransparentRegionHint(region);
+            mBackgroundControl.setTransparentRegionHint(region);
+        }
+
+        @Override
+        public void deferTransactionUntil(IBinder handle, long frame) {
+            super.deferTransactionUntil(handle, frame);
+            mBackgroundControl.deferTransactionUntil(handle, frame);
+        }
+
+        private void updateBackgroundVisibility() {
+            if (mOpaque && mVisible) {
+                mBackgroundControl.show();
+            } else {
+                mBackgroundControl.hide();
+            }
+        }
+    }
 }