OSDN Git Service

Merge "Don't resume activity if user is locked and encryption is unsupported" into...
authorBryce Lee <brycelee@google.com>
Fri, 18 Aug 2017 21:33:46 +0000 (21:33 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Fri, 18 Aug 2017 21:33:46 +0000 (21:33 +0000)
70 files changed:
api/current.txt
api/system-current.txt
api/test-current.txt
core/java/android/app/ActivityThread.java
core/java/android/app/Application.java
core/java/android/app/Notification.java
core/java/android/app/NotificationChannelGroup.java
core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
core/java/android/content/pm/PackageParser.java
core/java/android/net/IpPrefix.java
core/java/android/net/LinkAddress.java
core/java/android/net/NetworkCapabilities.java
core/java/android/util/Patterns.java
core/java/android/view/accessibility/AccessibilityManager.java
core/java/com/android/internal/notification/SystemNotificationChannels.java
core/res/res/values-mcc310-mnc030/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc170 [deleted symlink]
core/res/res/values-mcc310-mnc170/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc280/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc380 [deleted symlink]
core/res/res/values-mcc310-mnc380/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc410/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc560/strings.xml [new file with mode: 0644]
core/res/res/values-mcc310-mnc950/strings.xml [new file with mode: 0644]
core/res/res/values-mcc311-mnc180/strings.xml [new file with mode: 0644]
core/res/res/values/config.xml
core/res/res/values/strings.xml
core/res/res/values/symbols.xml
data/etc/framework-sysconfig.xml
packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java [deleted file]
packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
packages/SystemUI/res/layout/car_qs_panel.xml
packages/SystemUI/src/com/android/systemui/Dependency.java
packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java [deleted file]
packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
packages/SystemUI/src/com/android/systemui/recents/Recents.java
packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
services/autofill/java/com/android/server/autofill/RemoteFillService.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityRecord.java
services/core/java/com/android/server/am/TaskRecord.java
services/core/java/com/android/server/locksettings/LockSettingsService.java
services/core/java/com/android/server/net/NetworkPolicyManagerService.java
services/core/java/com/android/server/notification/ManagedServices.java
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/notification/RankingHelper.java
services/core/java/com/android/server/pm/Settings.java
services/core/java/com/android/server/wm/AppWindowContainerController.java
services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
telecomm/java/android/telecom/Call.java
telephony/java/android/telephony/CarrierConfigManager.java
telephony/java/android/telephony/ServiceState.java
telephony/java/android/telephony/TelephonyManager.java
tests/net/java/android/net/IpPrefixTest.java [moved from core/tests/coretests/src/android/net/IpPrefixTest.java with 93% similarity]
tests/net/java/android/net/LinkAddressTest.java [moved from core/tests/coretests/src/android/net/LinkAddressTest.java with 92% similarity]
wifi/java/android/net/wifi/RttManager.java

index 297854b..24ab586 100644 (file)
@@ -4214,12 +4214,6 @@ package android.app {
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -38883,7 +38877,7 @@ package android.telecom {
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
@@ -47205,6 +47199,7 @@ package android.view.accessibility {
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public void interrupt();
+    method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
index ec9ff67..9963268 100644 (file)
@@ -4378,12 +4378,6 @@ package android.app {
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -42128,7 +42122,7 @@ package android.telecom {
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
index 7c988ac..343228a 100644 (file)
@@ -4227,12 +4227,6 @@ package android.app {
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
-    method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onLowMemory();
@@ -39126,7 +39120,7 @@ package android.telecom {
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read() throws java.io.IOException;
+    method public java.lang.String read();
     method public java.lang.String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
     method public void write(java.lang.String) throws java.io.IOException;
@@ -47657,6 +47651,7 @@ package android.view.accessibility {
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public void interrupt();
+    method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
index 43693e1..2e4ce18 100644 (file)
@@ -2666,14 +2666,8 @@ public final class ActivityThread {
         Activity activity = null;
         try {
             java.lang.ClassLoader cl = appContext.getClassLoader();
-            if (appContext.getApplicationContext() instanceof Application) {
-                activity = ((Application) appContext.getApplicationContext())
-                        .instantiateActivity(cl, component.getClassName(), r.intent);
-            }
-            if (activity == null) {
-                activity = mInstrumentation.newActivity(
-                        cl, component.getClassName(), r.intent);
-            }
+            activity = mInstrumentation.newActivity(
+                    cl, component.getClassName(), r.intent);
             StrictMode.incrementExpectedActivityCount(activity.getClass());
             r.intent.setExtrasClassLoader(cl);
             r.intent.prepareToEnterProcess();
@@ -3169,8 +3163,7 @@ public final class ActivityThread {
             data.intent.setExtrasClassLoader(cl);
             data.intent.prepareToEnterProcess();
             data.setExtrasClassLoader(cl);
-            receiver = instantiate(cl, component, data.intent, app,
-                    Application::instantiateReceiver);
+            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
         } catch (Exception e) {
             if (DEBUG_BROADCAST) Slog.i(TAG,
                     "Finishing failed broadcast to " + data.intent.getComponent());
@@ -3258,13 +3251,12 @@ public final class ActivityThread {
             } else {
                 try {
                     if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname);
-                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
 
                     java.lang.ClassLoader cl = packageInfo.getClassLoader();
-                    agent = instantiate(cl, classname, context,
-                            Application::instantiateBackupAgent);
+                    agent = (BackupAgent) cl.loadClass(classname).newInstance();
 
                     // set up the agent's context
+                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                     context.setOuterContext(agent);
                     agent.attach(context);
 
@@ -3324,12 +3316,9 @@ public final class ActivityThread {
         LoadedApk packageInfo = getPackageInfoNoCheck(
                 data.info.applicationInfo, data.compatInfo);
         Service service = null;
-        Application app = null;
         try {
-            app = packageInfo.makeApplication(false, mInstrumentation);
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
-            service = instantiate(cl, data.info.name, data.intent, app,
-                    Application::instantiateService);
+            service = (Service) cl.loadClass(data.info.name).newInstance();
         } catch (Exception e) {
             if (!mInstrumentation.onException(service, e)) {
                 throw new RuntimeException(
@@ -3344,6 +3333,7 @@ public final class ActivityThread {
             ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
             context.setOuterContext(service);
 
+            Application app = packageInfo.makeApplication(false, mInstrumentation);
             service.attach(context, this, data.info.name, data.token, app,
                     ActivityManager.getService());
             service.onCreate();
@@ -5682,8 +5672,8 @@ public final class ActivityThread {
 
             try {
                 final ClassLoader cl = instrContext.getClassLoader();
-                mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),
-                        instrContext, Application::instantiateInstrumentation);
+                mInstrumentation = (Instrumentation)
+                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
             } catch (Exception e) {
                 throw new RuntimeException(
                     "Unable to instantiate instrumentation "
@@ -6234,8 +6224,8 @@ public final class ActivityThread {
 
             try {
                 final java.lang.ClassLoader cl = c.getClassLoader();
-                localProvider = instantiate(cl, info.name, context,
-                        Application::instantiateProvider);
+                localProvider = (ContentProvider)cl.
+                    loadClass(info.name).newInstance();
                 provider = localProvider.getIContentProvider();
                 if (provider == null) {
                     Slog.e(TAG, "Failed to instantiate class " +
@@ -6434,49 +6424,6 @@ public final class ActivityThread {
         }
     }
 
-    private <T> T instantiate(ClassLoader cl, String className, Context c,
-            Instantiator<T> instantiator)
-            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        Application app = getApp(c);
-        if (app != null) {
-            T a = instantiator.instantiate(app, cl, className);
-            if (a != null) return a;
-        }
-        return (T) cl.loadClass(className).newInstance();
-    }
-
-    private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
-            IntentInstantiator<T> instantiator)
-            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        Application app = getApp(c);
-        if (app != null) {
-            T a = instantiator.instantiate(app, cl, className, intent);
-            if (a != null) return a;
-        }
-        return (T) cl.loadClass(className).newInstance();
-    }
-
-    private Application getApp(Context c) {
-        // We need this shortcut to avoid actually calling getApplicationContext() on an Application
-        // because the Application may not return itself for getApplicationContext() because the
-        // API doesn't enforce it.
-        if (c instanceof Application) return (Application) c;
-        if (c.getApplicationContext() instanceof Application) {
-            return (Application) c.getApplicationContext();
-        }
-        return null;
-    }
-
-    private interface Instantiator<T> {
-        T instantiate(Application app, ClassLoader cl, String className)
-                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
-    }
-
-    private interface IntentInstantiator<T> {
-        T instantiate(Application app, ClassLoader cl, String className, Intent intent)
-                throws ClassNotFoundException, IllegalAccessException, InstantiationException;
-    }
-
     private static class EventLoggingReporter implements EventLogger.Reporter {
         @Override
         public void report (int code, Object... list) {
index cc23ec9..156df36 100644 (file)
 
 package android.app;
 
+import java.util.ArrayList;
+
 import android.annotation.CallSuper;
-import android.app.backup.BackupAgent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
-import android.content.ContentProvider;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 
-import java.util.ArrayList;
-
 /**
  * Base class for maintaining global application state. You can provide your own
  * implementation by creating a subclass and specifying the fully-qualified name
@@ -292,73 +289,4 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
             }
         }
     }
-
-    /**
-     * Allows application to override the creation of activities. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of receivers. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of services. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     * @param intent Intent creating the class.
-     */
-    public Service instantiateService(ClassLoader cl, String className, Intent intent) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of providers. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public ContentProvider instantiateProvider(ClassLoader cl, String className) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of backup agents. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) {
-        return null;
-    }
-
-    /**
-     * Allows application to override the creation of instrumentation. This can be used to
-     * perform things such as dependency injection or class loader changes to these
-     * classes. Return null to use the default creation flow.
-     * @param cl The default classloader to use for instantiation.
-     * @param className The class to be instantiated.
-     */
-    public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) {
-        return null;
-    }
 }
\ No newline at end of file
index dea1dbe..586f13f 100644 (file)
@@ -1164,7 +1164,8 @@ public class Notification implements Parcelable
      * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all children
      * notification in a group should be silenced (no sound or vibration) even if they are posted
      * to a {@link NotificationChannel} that has sound and/or vibration. Use this constant to
-     * mute this notification if this notification is a group child.
+     * mute this notification if this notification is a group child. This must be applied to all
+     * children notifications you want to mute.
      *
      * <p> For example, you might want to use this constant if you post a number of children
      * notifications at once (say, after a periodic sync), and only need to notify the user
@@ -1179,7 +1180,8 @@ public class Notification implements Parcelable
      * to mute this notification if this notification is a group summary.
      *
      * <p>For example, you might want to use this constant if only the children notifications
-     * in your group have content and the summary is only used to visually group notifications.
+     * in your group have content and the summary is only used to visually group notifications
+     * rather than to alert the user that new information is available.
      */
     public static final int GROUP_ALERT_CHILDREN = 2;
 
@@ -2914,7 +2916,9 @@ public class Notification implements Parcelable
          * Sets the group alert behavior for this notification. Use this method to mute this
          * notification if alerts for this notification's group should be handled by a different
          * notification. This is only applicable for notifications that belong to a
-         * {@link #setGroup(String) group}.
+         * {@link #setGroup(String) group}. This must be called on all notifications you want to
+         * mute. For example, if you want only the summary of your group to make noise, all
+         * children in the group should have the group alert behavior {@link #GROUP_ALERT_SUMMARY}.
          *
          * <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
          */
index 7e8f191..18ad9cf 100644 (file)
  */
 package android.app;
 
-import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.content.Intent;
-import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
-import android.util.Slog;
 
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -115,10 +109,8 @@ public final class NotificationChannelGroup implements Parcelable {
         return mName;
     }
 
-    /*
+    /**
      * Returns the list of channels that belong to this group
-     *
-     * @hide
      */
     public List<NotificationChannel> getChannels() {
         return mChannels;
index dfd5996..44c2667 100644 (file)
@@ -415,7 +415,8 @@ public final class BluetoothLeAdvertiser {
           gatt = mBluetoothManager.getBluetoothGatt();
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
-          throw new IllegalStateException("Failed to get Bluetooth");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
 
         IAdvertisingSetCallback wrapped = wrap(callback, handler);
@@ -429,7 +430,8 @@ public final class BluetoothLeAdvertiser {
                                      periodicData, duration, maxExtendedAdvertisingEvents, wrapped);
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to start advertising set - ", e);
-          throw new IllegalStateException("Failed to start advertising set");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
     }
 
@@ -453,8 +455,7 @@ public final class BluetoothLeAdvertiser {
             gatt.stopAdvertisingSet(wrapped);
        } catch (RemoteException e) {
             Log.e(TAG, "Failed to stop advertising - ", e);
-            throw new IllegalStateException("Failed to stop advertising");
-        }
+       }
     }
 
     /**
@@ -648,6 +649,16 @@ public final class BluetoothLeAdvertiser {
         };
     }
 
+    private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback,
+        final int error) {
+        handler.post(new Runnable() {
+              @Override
+              public void run() {
+                  callback.onAdvertisingSetStarted(null, 0, error);
+              }
+          });
+    }
+
     private void postStartFailure(final AdvertiseCallback callback, final int error) {
         mHandler.post(new Runnable() {
             @Override
index 9b9499c..7ae8522 100644 (file)
@@ -1120,12 +1120,12 @@ public class PackageParser {
         final String cacheKey = getCacheKey(packageFile, flags);
         final File cacheFile = new File(mCacheDir, cacheKey);
 
-        // If the cache is not up to date, return null.
-        if (!isCacheUpToDate(packageFile, cacheFile)) {
-            return null;
-        }
-
         try {
+            // If the cache is not up to date, return null.
+            if (!isCacheUpToDate(packageFile, cacheFile)) {
+                return null;
+            }
+
             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
             Package p = fromCacheEntry(bytes);
             if (mCallback != null) {
@@ -1140,7 +1140,7 @@ public class PackageParser {
                 }
             }
             return p;
-        } catch (Exception e) {
+        } catch (Throwable e) {
             Slog.w(TAG, "Error reading package cache: ", e);
 
             // If something went wrong while reading the cache entry, delete the cache file
@@ -1158,26 +1158,30 @@ public class PackageParser {
             return;
         }
 
-        final String cacheKey = getCacheKey(packageFile, flags);
-        final File cacheFile = new File(mCacheDir, cacheKey);
+        try {
+            final String cacheKey = getCacheKey(packageFile, flags);
+            final File cacheFile = new File(mCacheDir, cacheKey);
 
-        if (cacheFile.exists()) {
-            if (!cacheFile.delete()) {
-                Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+            if (cacheFile.exists()) {
+                if (!cacheFile.delete()) {
+                    Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+                }
             }
-        }
 
-        final byte[] cacheEntry = toCacheEntry(parsed);
+            final byte[] cacheEntry = toCacheEntry(parsed);
 
-        if (cacheEntry == null) {
-            return;
-        }
+            if (cacheEntry == null) {
+                return;
+            }
 
-        try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
-            fos.write(cacheEntry);
-        } catch (IOException ioe) {
-            Slog.w(TAG, "Error writing cache entry.", ioe);
-            cacheFile.delete();
+            try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
+                fos.write(cacheEntry);
+            } catch (IOException ioe) {
+                Slog.w(TAG, "Error writing cache entry.", ioe);
+                cacheFile.delete();
+            }
+        } catch (Throwable e) {
+            Slog.w(TAG, "Error saving package cache.", e);
         }
     }
 
index 6b4f2d5..6e2654e 100644 (file)
@@ -20,6 +20,8 @@ import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Pair;
 
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -185,6 +187,20 @@ public final class IpPrefix implements Parcelable {
     }
 
     /**
+     * @hide
+     */
+    public boolean isIPv6() {
+        return getAddress() instanceof Inet6Address;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isIPv4() {
+        return getAddress() instanceof Inet4Address;
+    }
+
+    /**
      * Returns a string representation of this {@code IpPrefix}.
      *
      * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
index 62de991..bcfe938 100644 (file)
@@ -76,7 +76,7 @@ public class LinkAddress implements Parcelable {
      * RFC 6724 section 3.2.
      * @hide
      */
-    static int scopeForUnicastAddress(InetAddress addr) {
+    private static int scopeForUnicastAddress(InetAddress addr) {
         if (addr.isAnyLocalAddress()) {
             return RT_SCOPE_HOST;
         }
@@ -101,7 +101,7 @@ public class LinkAddress implements Parcelable {
      * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
      */
     private boolean isIPv6ULA() {
-        if (address instanceof Inet6Address) {
+        if (isIPv6()) {
             byte[] bytes = address.getAddress();
             return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
         }
@@ -109,13 +109,29 @@ public class LinkAddress implements Parcelable {
     }
 
     /**
+     * @return true if the address is IPv6.
+     * @hide
+     */
+    public boolean isIPv6() {
+        return address instanceof Inet6Address;
+    }
+
+    /**
+     * @return true if the address is IPv4 or is a mapped IPv4 address.
+     * @hide
+     */
+    public boolean isIPv4() {
+        return address instanceof Inet4Address;
+    }
+
+    /**
      * Utility function for the constructors.
      */
     private void init(InetAddress address, int prefixLength, int flags, int scope) {
         if (address == null ||
                 address.isMulticastAddress() ||
                 prefixLength < 0 ||
-                ((address instanceof Inet4Address) && prefixLength > 32) ||
+                (address instanceof Inet4Address && prefixLength > 32) ||
                 (prefixLength > 128)) {
             throw new IllegalArgumentException("Bad LinkAddress params " + address +
                     "/" + prefixLength);
@@ -184,6 +200,7 @@ public class LinkAddress implements Parcelable {
      */
     public LinkAddress(String address, int flags, int scope) {
         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
+        // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
         init(ipAndMask.first, ipAndMask.second, flags, scope);
     }
index 0b92893..4bb8844 100644 (file)
@@ -770,7 +770,6 @@ public final class NetworkCapabilities implements Parcelable {
 
         StringJoiner joiner = new StringJoiner(", ");
 
-        // TODO: consider only enforcing that capabilities are not removed, allowing addition.
         // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
         // TODO: properly support NOT_METERED as a mutable and requestable capability.
         final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
index ca39854..50cd7b1 100644 (file)
@@ -406,7 +406,7 @@ public class Patterns {
      * the local part to be at most 64 octets.
      */
     private static final String EMAIL_ADDRESS_LOCAL_PART =
-            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?";
+            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{0,62}[" + EMAIL_CHAR + "])?";
 
     /**
      * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits
index d9128d8..0b9bc57 100644 (file)
@@ -23,7 +23,6 @@ import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.ComponentName;
 import android.content.Context;
@@ -1113,9 +1112,7 @@ public final class AccessibilityManager {
      *
      * @return {@code true} if the accessibility button is supported on this device,
      * {@code false} otherwise
-     * @hide
      */
-    @SystemApi
     public static boolean isAccessibilityButtonSupported() {
         final Resources res = Resources.getSystem();
         return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
index d327180..d64c9a1 100644 (file)
@@ -132,10 +132,12 @@ public class SystemNotificationChannels {
                 context.getString(R.string.notification_channel_usb),
                 NotificationManager.IMPORTANCE_MIN));
 
-        channelsList.add(new NotificationChannel(
+        NotificationChannel foregroundChannel = new NotificationChannel(
                 FOREGROUND_SERVICE,
                 context.getString(R.string.notification_channel_foreground_service),
-                NotificationManager.IMPORTANCE_LOW));
+                NotificationManager.IMPORTANCE_LOW);
+        foregroundChannel.setBlockableSystem(true);
+        channelsList.add(foregroundChannel);
 
         nm.createNotificationChannels(channelsList);
     }
diff --git a/core/res/res/values-mcc310-mnc030/strings.xml b/core/res/res/values-mcc310-mnc030/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc170 b/core/res/res/values-mcc310-mnc170
deleted file mode 120000 (symlink)
index cfced17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./values-mcc310-mnc150
\ No newline at end of file
diff --git a/core/res/res/values-mcc310-mnc170/strings.xml b/core/res/res/values-mcc310-mnc170/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc280/strings.xml b/core/res/res/values-mcc310-mnc280/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc380 b/core/res/res/values-mcc310-mnc380
deleted file mode 120000 (symlink)
index cfced17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./values-mcc310-mnc150
\ No newline at end of file
diff --git a/core/res/res/values-mcc310-mnc380/strings.xml b/core/res/res/values-mcc310-mnc380/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc410/strings.xml b/core/res/res/values-mcc310-mnc410/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc560/strings.xml b/core/res/res/values-mcc310-mnc560/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc950/strings.xml b/core/res/res/values-mcc310-mnc950/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
diff --git a/core/res/res/values-mcc311-mnc180/strings.xml b/core/res/res/values-mcc311-mnc180/strings.xml
new file mode 100644 (file)
index 0000000..a3fea29
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string>
+    <string name="mmcc_illegal_ms">SIM not allowed MM#3</string>
+</resources>
index 95aa264..ca4b355 100644 (file)
     <!-- Integer parameters of the wifi to cellular handover feature
          wifi should not stick to bad networks -->
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-82</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-85</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_5">12</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer>
+
     <string  translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string>
     <string  translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string>
 
     <bool name="config_automatic_brightness_available">false</bool>
 
     <!-- Fast brightness animation ramp rate in brightness units per second-->
-    <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+    <integer translatable="false" name="config_brightness_ramp_rate_fast">180</integer>
 
     <!-- Slow brightness animation ramp rate in brightness units per second-->
-    <integer translatable="false" name="config_brightness_ramp_rate_slow">40</integer>
+    <integer translatable="false" name="config_brightness_ramp_rate_slow">60</integer>
 
     <!-- Don't name config resources like this.  It should look like config_annoyDianne -->
     <bool name="config_annoy_dianne">true</bool>
index 8a5625b..ce6815f 100644 (file)
     <!-- This is the label for the notification channel settings that controls the behavior
         of the notification about applications that are running in the background (that is,
         perhaps confusingly, running foreground services but not the foreground UI on the screen).
-        [CHAR LIMIT=NONE] -->
-    <string name="notification_channel_foreground_service">Apps running in background</string>
+        [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6665375982962336520] -->
+    <string name="notification_channel_foreground_service">Apps consuming battery</string>
 
-    <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] -->
+    <!-- Label for foreground service notification when one app is running.
+    [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] -->
     <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
-        running in the background</string>
+        using battery</string>
 
     <!-- Label for foreground service notification when multiple apps are running.
-        [CHAR LIMIT=NONE] -->
+        [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7150914856893450380] -->
     <string name="foreground_service_apps_in_background"><xliff:g id="number">%1$d</xliff:g> apps
-        are running in the background</string>
+        are using battery</string>
 
     <!-- Content for foreground service notification when one app is running.
         [CHAR LIMIT=NONE] -->
index af08e24..04cfe48 100644 (file)
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_max_total_dwell_time" />
   <java-symbol type="integer" name="config_wifi_framework_associated_partial_scan_max_num_active_channels" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz" />
+  <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz" />
+  <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz" />
   <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_link_speed_24" />
index 3a81c13..ae6a7f6 100644 (file)
@@ -22,6 +22,8 @@
     <allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" />
     <allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
     <allow-implicit-broadcast action="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
+    <allow-implicit-broadcast action="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION" />
+    <allow-implicit-broadcast action="android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION" />
 
     <!-- Whitelist of what components are permitted as backup data transports.  The
          'service' attribute here is a flattened ComponentName string. -->
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java
deleted file mode 100644 (file)
index 925214e..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package com.android.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Bundle;
-
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A PluginActivity is an activity that replaces another full activity (e.g. RecentsActivity)
- * at runtime within the sysui process.
- */
-@ProvidesInterface(version = PluginActivity.VERSION)
-public abstract class PluginActivity extends Activity implements Plugin {
-
-    public static final int VERSION = 1;
-
-    public static final String ACTION_RECENTS = "com.android.systemui.action.PLUGIN_RECENTS";
-
-    private Context mSysuiContext;
-    private boolean mSettingActionBar;
-
-    @Override
-    public final void onCreate(Context sysuiContext, Context pluginContext) {
-        mSysuiContext = sysuiContext;
-        super.attachBaseContext(pluginContext);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Theme theme = getClass().getDeclaredAnnotation(Theme.class);
-        if (theme != null && theme.value() != 0) {
-            setTheme(theme.value());
-        }
-        mSettingActionBar = true;
-        getActionBar();
-        mSettingActionBar = false;
-    }
-
-    @Override
-    public Resources getResources() {
-        return mSettingActionBar ? mSysuiContext.getResources() : super.getResources();
-    }
-
-    @Override
-    protected void attachBaseContext(Context newBase) {
-        mSysuiContext = newBase;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-    }
-
-    public Context getSysuiContext() {
-        return mSysuiContext;
-    }
-
-    public Context getPluginContext() {
-        return getBaseContext();
-    }
-
-    /**
-     * Since PluginActivities are declared as services instead of activities (since they
-     * are plugins), they can't have a theme attached to them. Instead a PluginActivity
-     * can annotate itself with @Theme to specify the resource of the style it wants
-     * to be themed with.
-     */
-    @Retention(RetentionPolicy.RUNTIME)
-    public @interface Theme {
-        int value();
-    }
-}
index db2e376..25ce3dd 100644 (file)
@@ -21,11 +21,6 @@ public class PluginDependency {
     public static final int VERSION = 1;
     static DependencyProvider sProvider;
 
-    /**
-     * Allows a plugin to get a hold of static dependencies if they have declared dependence
-     * on their interface. For one-shot plugins this will only work during onCreate and will
-     * not work afterwards.
-     */
     public static <T> T get(Plugin p, Class<T> cls) {
         return sProvider.get(p, cls);
     }
index d1f7ff8..0b46b0b 100644 (file)
 
     <include layout="@layout/car_status_bar_header" />
     <include layout="@layout/car_qs_footer" />
+
+    <com.android.systemui.statusbar.car.UserGridView
+        android:id="@+id/user_grid"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/car_margin"
+        android:layout_marginRight="@dimen/car_margin" />
 </LinearLayout>
index ecc2111..49253ec 100644 (file)
@@ -34,7 +34,6 @@ import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.PluginManagerImpl;
@@ -295,8 +294,6 @@ public class Dependency extends SystemUI {
 
         mProviders.put(UiOffloadThread.class, UiOffloadThread::new);
 
-        mProviders.put(PluginActivityManager.class,
-                () -> new PluginActivityManager(mContext, getDependency(PluginManager.class)));
 
         mProviders.put(PowerUI.WarningsUI.class, () -> new PowerNotificationWarnings(mContext));
 
index 49a076f..9adafda 100644 (file)
@@ -16,7 +16,6 @@
 
 package com.android.systemui;
 
-import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.BroadcastReceiver;
@@ -41,7 +40,6 @@ import com.android.systemui.pip.PipUI;
 import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.power.PowerUI;
@@ -281,10 +279,4 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
     public SystemUI[] getServices() {
         return mServices;
     }
-
-    @Override
-    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
-        if (!mServicesStarted) return null;
-        return Dependency.get(PluginActivityManager.class).instantiate(cl, className, intent);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java
deleted file mode 100644 (file)
index 9becc38..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package com.android.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-
-public class PluginActivityManager {
-
-    private final Context mContext;
-    private final PluginManager mPluginManager;
-    private final ArrayMap<String, String> mActionLookup = new ArrayMap<>();
-
-    public PluginActivityManager(Context context, PluginManager pluginManager) {
-        mContext = context;
-        mPluginManager = pluginManager;
-    }
-
-    public void addActivityPlugin(String className, String action) {
-        mActionLookup.put(className, action);
-    }
-
-    public Activity instantiate(ClassLoader cl, String className, Intent intent) {
-        String action = mActionLookup.get(className);
-        if (TextUtils.isEmpty(action)) return null;
-        return mPluginManager.getOneShotPlugin(action, PluginActivity.class);
-    }
-}
index a968399..493d244 100644 (file)
@@ -42,6 +42,7 @@ import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
 import dalvik.system.PathClassLoader;
@@ -119,21 +120,14 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
         }
         PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
                 false, mLooper, cls, this);
-        PluginListener<Plugin> listener = new PluginListener<Plugin>() {
-            @Override
-            public void onPluginConnected(Plugin plugin, Context pluginContext) { }
-        };
-        mPluginMap.put(listener, p);
         mPluginPrefs.addAction(action);
-        PluginInstanceManager.PluginInfo<T> info = p.getPlugin();
+        PluginInfo<T> info = p.getPlugin();
         if (info != null) {
             mOneShotPackages.add(info.mPackage);
             mHasOneShot = true;
             startListening();
-            mPluginMap.remove(listener);
             return info.mPlugin;
         }
-        mPluginMap.remove(listener);
         return null;
     }
 
index e574c01..a48bcbd 100644 (file)
@@ -310,11 +310,47 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic
             vpnWarning.setMovementMethod(new LinkMovementMethod());
         }
 
+        // Note: if a new section is added, should update configSubtitleVisibility to include
+        // the handling of the subtitle
+        configSubtitleVisibility(managementMessage != null,
+                caCertsMessage != null,
+                networkLoggingMessage != null,
+                vpnMessage != null,
+                dialogView);
+
         mDialog.show();
         mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
     }
 
+    protected void configSubtitleVisibility(boolean showDeviceManagement, boolean showCaCerts,
+            boolean showNetworkLogging, boolean showVpn, View dialogView) {
+        // Device Management title should always been shown
+        // When there is a Device Management message, all subtitles should be shown
+        if (showDeviceManagement) {
+            return;
+        }
+        // Hide the subtitle if there is only 1 message shown
+        int mSectionCountExcludingDeviceMgt = 0;
+        if (showCaCerts) { mSectionCountExcludingDeviceMgt++; }
+        if (showNetworkLogging) { mSectionCountExcludingDeviceMgt++; }
+        if (showVpn) { mSectionCountExcludingDeviceMgt++; }
+
+        // No work needed if there is no sections or more than 1 section
+        if (mSectionCountExcludingDeviceMgt != 1) {
+            return;
+        }
+        if (showCaCerts) {
+            dialogView.findViewById(R.id.ca_certs_subtitle).setVisibility(View.GONE);
+        }
+        if (showNetworkLogging) {
+            dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
+        }
+        if (showVpn) {
+            dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
+        }
+    }
+
     private String getSettingsButton() {
         return mContext.getString(R.string.monitoring_button_view_policies);
     }
index 9730f29..d42b87b 100644 (file)
@@ -18,6 +18,7 @@ import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
@@ -27,6 +28,7 @@ import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.QSFooter;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.statusbar.car.UserGridView;
 import com.android.systemui.statusbar.phone.MultiUserSwitch;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -37,10 +39,13 @@ import com.android.systemui.statusbar.policy.UserInfoController;
  */
 public class CarQSFooter extends RelativeLayout implements QSFooter,
         UserInfoController.OnUserInfoChangedListener {
+    private static final String TAG = "CarQSFooter";
+
     private UserInfoController mUserInfoController;
 
     private MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
+    private UserGridView mUserGridView;
 
     public CarQSFooter(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -54,6 +59,19 @@ public class CarQSFooter extends RelativeLayout implements QSFooter,
 
         mUserInfoController = Dependency.get(UserInfoController.class);
 
+        mMultiUserSwitch.setOnClickListener(v -> {
+            if (mUserGridView == null) {
+                Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher.");
+                return;
+            }
+
+            if (!mUserGridView.isShowing()) {
+                mUserGridView.show();
+            } else {
+                mUserGridView.hide();
+            }
+        });
+
         findViewById(R.id.settings_button).setOnClickListener(v -> {
             ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
 
@@ -80,6 +98,10 @@ public class CarQSFooter extends RelativeLayout implements QSFooter,
         }
     }
 
+    public void setUserGridView(UserGridView view) {
+        mUserGridView = view;
+    }
+
     @Override
     public void setListening(boolean listening) {
         if (listening) {
index 7c2a812..13298d3 100644 (file)
@@ -22,9 +22,12 @@ import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFooter;
+import com.android.systemui.statusbar.car.UserGridView;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 /**
  * A quick settings fragment for the car. For auto, there is no row for quick settings or ability
@@ -33,7 +36,8 @@ import com.android.systemui.qs.QSFooter;
  */
 public class CarQSFragment extends Fragment implements QS {
     private View mHeader;
-    private QSFooter mFooter;
+    private CarQSFooter mFooter;
+    private UserGridView mUserGridView;
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -46,6 +50,12 @@ public class CarQSFragment extends Fragment implements QS {
         super.onViewCreated(view, savedInstanceState);
         mHeader = view.findViewById(R.id.header);
         mFooter = view.findViewById(R.id.qs_footer);
+
+        mUserGridView = view.findViewById(R.id.user_grid);
+        mUserGridView.init(null, Dependency.get(UserSwitcherController.class),
+                false /* showInitially */);
+
+        mFooter.setUserGridView(mUserGridView);
     }
 
     @Override
index d10e080..4a8b43e 100644 (file)
@@ -43,14 +43,11 @@ import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
-import com.android.systemui.plugins.PluginActivity;
-import com.android.systemui.plugins.PluginActivityManager;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -239,8 +236,6 @@ public class Recents extends SystemUI
             registerWithSystemUser();
         }
         putComponent(Recents.class, this);
-        Dependency.get(PluginActivityManager.class).addActivityPlugin(RecentsImpl.RECENTS_ACTIVITY,
-                PluginActivity.ACTION_RECENTS);
     }
 
     @Override
index 6060134..172c62a 100644 (file)
@@ -53,7 +53,7 @@ public class FullscreenUserSwitcher {
         mParent = containerStub.inflate();
         mContainer = mParent.findViewById(R.id.container);
         mUserGridView = mContainer.findViewById(R.id.user_grid);
-        mUserGridView.init(statusBar, mUserSwitcherController);
+        mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */);
         mUserGridView.setUserSelectionListener(record -> {
             if (!record.isCurrent) {
                 toggleSwitchInProgress(true);
index f178aa6..e551801 100644 (file)
 
 package com.android.systemui.statusbar.car;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Paint.Align;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
-import android.os.UserHandle;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,9 +38,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.internal.util.UserIcons;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.UserUtil;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
@@ -48,21 +47,44 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
  * One of the uses of this is for the lock screen in auto.
  */
 public class UserGridView extends ViewPager {
+    private static final int EXPAND_ANIMATION_TIME_MS = 200;
+    private static final int HIDE_ANIMATION_TIME_MS = 133;
+
     private StatusBar mStatusBar;
     private UserSwitcherController mUserSwitcherController;
     private Adapter mAdapter;
     private UserSelectionListener mUserSelectionListener;
+    private ValueAnimator mHeightAnimator;
+    private int mTargetHeight;
+    private int mHeightChildren;
+    private boolean mShowing;
 
     public UserGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) {
+    public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
+            boolean showInitially) {
         mStatusBar = statusBar;
         mUserSwitcherController = userSwitcherController;
         mAdapter = new Adapter(mUserSwitcherController);
         addOnLayoutChangeListener(mAdapter);
         setAdapter(mAdapter);
+        mShowing = showInitially;
+    }
+
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    public void show() {
+        mShowing = true;
+        animateHeightChange(getMeasuredHeight(), mHeightChildren);
+    }
+
+    public void hide() {
+        mShowing = false;
+        animateHeightChange(getMeasuredHeight(), 0);
     }
 
     public void onUserSwitched(int newUserId) {
@@ -83,16 +105,85 @@ public class UserGridView extends ViewPager {
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
         int height = 0;
-        for(int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            child.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-            height = Math.max(child.getMeasuredHeight(), height);
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
+            height = MeasureSpec.getSize(heightMeasureSpec);
+        } else {
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                child.measure(widthMeasureSpec,
+                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+                height = Math.max(child.getMeasuredHeight(), height);
+            }
+
+            mHeightChildren = height;
+
+            // Override the height if it's not showing.
+            if (!mShowing) {
+                height = 0;
+            }
+
+            // Respect the AT_MOST request from parent.
+            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+                height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height);
+            }
         }
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
+    private void animateHeightChange(int oldHeight, int newHeight) {
+        // If there is no change in height or an animation is already in progress towards the
+        // desired height, then there's no need to make any changes.
+        if (oldHeight == newHeight || newHeight == mTargetHeight) {
+            return;
+        }
+
+        // Animation in progress is not going towards the new target, so cancel it.
+        if (mHeightAnimator != null){
+            mHeightAnimator.cancel();
+        }
+
+        mTargetHeight = newHeight;
+        mHeightAnimator = ValueAnimator.ofInt(oldHeight, mTargetHeight);
+        mHeightAnimator.addUpdateListener(valueAnimator -> {
+            ViewGroup.LayoutParams layoutParams = getLayoutParams();
+            layoutParams.height = (Integer) valueAnimator.getAnimatedValue();
+            requestLayout();
+        });
+        mHeightAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animator) {}
+
+            @Override
+            public void onAnimationEnd(Animator animator) {
+                // ValueAnimator does not guarantee that the update listener will get an update
+                // to the final value, so here, the final value is set.  Though the final calculated
+                // height (mTargetHeight) could be set, WRAP_CONTENT is more appropriate.
+                ViewGroup.LayoutParams layoutParams = getLayoutParams();
+                layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+                requestLayout();
+                mHeightAnimator = null;
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animator) {}
+
+            @Override
+            public void onAnimationRepeat(Animator animator) {}
+        });
+
+        mHeightAnimator.setInterpolator(new FastOutSlowInInterpolator());
+        if (oldHeight < newHeight) {
+            // Expanding
+            mHeightAnimator.setDuration(EXPAND_ANIMATION_TIME_MS);
+        } else {
+            // Hiding
+            mHeightAnimator.setDuration(HIDE_ANIMATION_TIME_MS);
+        }
+        mHeightAnimator.start();
+    }
+
     /**
      * This is a ViewPager.PagerAdapter which deletegates the work to a
      * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have
index 844a2c4..3115361 100644 (file)
 
 package com.android.systemui.statusbar.notification;
 
+import android.content.Context;
 import android.graphics.Color;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -57,4 +60,10 @@ public class NotificationUtils {
         offsetView.getLocationOnScreen(sLocationOffset);
         return sLocationOffset[1] - sLocationBase[1];
     }
+
+    public static boolean isHapticFeedbackDisabled(Context context) {
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
+    }
+
 }
index c45c05e..f06dd7b 100644 (file)
@@ -54,6 +54,7 @@ public class DozeScrimController {
     private boolean mFullyPulsing;
 
     private float mAodFrontScrimOpacity = 0;
+    private Runnable mSetDozeInFrontAlphaDelayed;
 
     public DozeScrimController(ScrimController scrimController, Context context) {
         mContext = context;
@@ -69,8 +70,7 @@ public class DozeScrimController {
             mDozingAborted = false;
             abortAnimations();
             mScrimController.setDozeBehindAlpha(1f);
-            mScrimController.setDozeInFrontAlpha(
-                    mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
+            setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
         } else {
             cancelPulsing();
             if (animate) {
@@ -83,7 +83,7 @@ public class DozeScrimController {
             } else {
                 abortAnimations();
                 mScrimController.setDozeBehindAlpha(0f);
-                mScrimController.setDozeInFrontAlpha(0f);
+                setDozeInFrontAlpha(0f);
             }
         }
     }
@@ -97,7 +97,7 @@ public class DozeScrimController {
         mAodFrontScrimOpacity = scrimOpacity;
         if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
                 && mDozeParameters.getAlwaysOn()) {
-            mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+            setDozeInFrontAlpha(mAodFrontScrimOpacity);
         }
     }
 
@@ -107,7 +107,7 @@ public class DozeScrimController {
         if (!mWakeAndUnlocking) {
             mWakeAndUnlocking = true;
             mScrimController.setDozeBehindAlpha(0f);
-            mScrimController.setDozeInFrontAlpha(0f);
+            setDozeInFrontAlpha(0f);
         }
     }
 
@@ -127,7 +127,7 @@ public class DozeScrimController {
         // be invoked when we're done so that the caller can drop the pulse wakelock.
         mPulseCallback = callback;
         mPulseReason = reason;
-        mScrimController.setDozeInFrontAlpha(1f);
+        setDozeInFrontAlpha(1f);
         mHandler.post(mPulseIn);
     }
 
@@ -138,9 +138,8 @@ public class DozeScrimController {
         cancelPulsing();
         if (mDozing && !mWakeAndUnlocking) {
             mScrimController.setDozeBehindAlpha(1f);
-            mScrimController.setDozeInFrontAlpha(
-                    mDozeParameters.getAlwaysOn() && !mDozingAborted ?
-                            mAodFrontScrimOpacity : 1f);
+            setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() && !mDozingAborted
+                    ? mAodFrontScrimOpacity : 1f);
         }
     }
 
@@ -295,6 +294,25 @@ public class DozeScrimController {
                 : mScrimController.getDozeBehindAlpha();
     }
 
+    private void setDozeInFrontAlpha(float opacity) {
+        setDozeInFrontAlphaDelayed(opacity, 0 /* delay */);
+
+    }
+
+    private void setDozeInFrontAlphaDelayed(float opacity, long delayMs) {
+        if (mSetDozeInFrontAlphaDelayed != null) {
+            mHandler.removeCallbacks(mSetDozeInFrontAlphaDelayed);
+            mSetDozeInFrontAlphaDelayed = null;
+        }
+        if (delayMs < 0) {
+            mScrimController.setDozeInFrontAlpha(opacity);
+        } else {
+            mHandler.postDelayed(mSetDozeInFrontAlphaDelayed = () -> {
+                setDozeInFrontAlpha(opacity);
+            }, delayMs);
+        }
+    }
+
     private final Runnable mPulseIn = new Runnable() {
         @Override
         public void run() {
@@ -364,7 +382,9 @@ public class DozeScrimController {
             // Signal that the pulse is all finished so we can turn the screen off now.
             DozeScrimController.this.pulseFinished();
             if (mDozeParameters.getAlwaysOn()) {
-                mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+                // Setting power states can happen after we push out the frame. Make sure we
+                // stay fully opaque until the power state request reaches the lower levels.
+                setDozeInFrontAlphaDelayed(mAodFrontScrimOpacity, 30);
             }
         }
     };
index c241290..5c9446c 100644 (file)
@@ -207,9 +207,9 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
         if (mAccessibilityController == null) {
             return;
         }
-        boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
+        boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
         boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
-                && !mAccessibilityController.isAccessibilityEnabled();
+                && !clickToUnlock;
         boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
index e0d9748..88a5626 100644 (file)
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.support.v4.util.ArrayMap;
 import android.support.v4.util.ArraySet;
 import android.util.AttributeSet;
@@ -34,6 +39,7 @@ import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.stack.AnimationFilter;
 import com.android.systemui.statusbar.stack.AnimationProperties;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -623,9 +629,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
                 boolean wasInShelf = icon.isInShelf();
                 boolean inShelf = iconAppearAmount == 1.0f;
                 icon.setIsInShelf(inShelf);
-                if (mVibrateOnAnimation && !justAdded && mAnimationsEnabled
-                        && wasInShelf != inShelf) {
-                    mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK));
+                if (shouldVibrateChange(wasInShelf != inShelf)) {
+                    AsyncTask.execute(
+                            () -> mVibrator.vibrate(VibrationEffect.get(
+                                    VibrationEffect.EFFECT_TICK)));
                 }
             }
             justAdded = false;
@@ -634,6 +641,25 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
             justUndarkened = false;
         }
 
+        private boolean shouldVibrateChange(boolean inShelfChanged) {
+            if (!mVibrateOnAnimation) {
+                return false;
+            }
+            if (justAdded) {
+                return false;
+            }
+            if (!mAnimationsEnabled) {
+                return false;
+            }
+            if (!inShelfChanged) {
+                return false;
+            }
+            if (isHapticFeedbackDisabled(mContext)) {
+                return false;
+            }
+            return true;
+        }
+
         public boolean hasCustomTransformHeight() {
             return isLastExpandIcon && customTransformHeight != NO_VALUE;
         }
index d3ee550..46f9c04 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -23,9 +25,12 @@ import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.AsyncTask;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -45,6 +50,7 @@ import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.io.FileDescriptor;
@@ -59,6 +65,7 @@ public abstract class PanelView extends FrameLayout {
     private float mMinExpandHeight;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mPanelUpdateWhenAnimatorEnds;
+    private boolean mVibrateOnOpening;
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -203,6 +210,8 @@ public abstract class PanelView extends FrameLayout {
         mNotificationsDragEnabled =
                 getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
         mVibrator = mContext.getSystemService(Vibrator.class);
+        mVibrateOnOpening = mContext.getResources().getBoolean(
+                R.bool.config_vibrateOnIconAnimation);
     }
 
     protected void loadDimens() {
@@ -394,7 +403,10 @@ public abstract class PanelView extends FrameLayout {
         runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
                 false /* collapseWhenFinished */);
         notifyBarPanelExpansionChanged();
-        mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+        if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) {
+            AsyncTask.execute(
+                    () -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK)));
+        }
     }
 
     protected abstract float getOpeningHeight();
index bba982c..b8e9fcd 100644 (file)
@@ -26,6 +26,8 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -34,10 +36,11 @@ import android.testing.TestableLooper.RunWithLooper;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
 import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
index a8487b3..4f98836 100644 (file)
@@ -29,6 +29,7 @@ import android.provider.Settings;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableStringBuilder;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -395,6 +396,57 @@ public class QSSecurityFooterTest extends SysuiTestCase {
                      mFooter.getVpnMessage(false, true, VPN_PACKAGE, null));
     }
 
+    @Test
+    public void testConfigSubtitleVisibility() {
+        View view = LayoutInflater.from(mContext)
+                .inflate(R.layout.quick_settings_footer_dialog, null);
+
+        // Device Management subtitle should be shown when there is Device Management section only
+        // Other sections visibility will be set somewhere else so it will not be tested here
+        mFooter.configSubtitleVisibility(true, false, false, false, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown
+        mFooter.configSubtitleVisibility(true, true, false, false, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown
+        mFooter.configSubtitleVisibility(true, true, true, true, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.device_management_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+        // If there are multiple sections, all subtitles should be shown, event if there is no
+        // Device Management section
+        mFooter.configSubtitleVisibility(false, true, true, true, view);
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        assertEquals(View.VISIBLE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+        // If there is only 1 section, the title should be hidden
+        mFooter.configSubtitleVisibility(false, true, false, false, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+        mFooter.configSubtitleVisibility(false, false, true, false, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.network_logging_subtitle).getVisibility());
+        mFooter.configSubtitleVisibility(false, false, false, true, view);
+        assertEquals(View.GONE,
+                view.findViewById(R.id.vpn_subtitle).getVisibility());
+    }
+
     private CharSequence addLink(CharSequence description) {
         final SpannableStringBuilder message = new SpannableStringBuilder();
         message.append(description);
index 2a2797c..f8c0e27 100644 (file)
@@ -562,7 +562,10 @@ final class RemoteFillService implements DeathRecipient {
         void onTimeout(RemoteFillService remoteService) {
             // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
             // handled by the service, which could block.
-            remoteService.dispatchOnFillTimeout(mCancellation);
+            final ICancellationSignal cancellation = mCancellation;
+            if (cancellation != null) {
+                remoteService.dispatchOnFillTimeout(cancellation);
+            }
             remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
         }
 
index ac41079..5110929 100644 (file)
@@ -4582,11 +4582,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
      */
     private void updateCapabilities(
             int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
-        // Sanity check: a NetworkAgent should not change its static capabilities or parameters.
-        if (nai.everConnected) {
+        // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
+        if (nai.everConnected &&
+                !nai.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities)) {
+            // TODO: consider not complaining when a network agent degrade its capabilities if this
+            // does not cause any request (that is not a listen) currently matching that agent to
+            // stop being matched by the updated agent.
             String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities);
             if (!TextUtils.isEmpty(diff)) {
-                Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities:" + diff);
+                Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
index 325ffb4..30e5a2c 100644 (file)
@@ -28,6 +28,7 @@ import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -3230,6 +3231,18 @@ public class ActivityManagerService extends IActivityManager.Stub
     }
 
     final void applyUpdateVrModeLocked(ActivityRecord r) {
+        // VR apps are expected to run in a main display. If an app is turning on VR for
+        // itself, but lives in a dynamic stack, then make sure that it is moved to the main
+        // fullscreen stack before enabling VR Mode.
+        // TODO: The goal of this code is to keep the VR app on the main display. When the
+        // stack implementation changes in the future, keep in mind that the use of the fullscreen
+        // stack is a means to move the activity to the main display and a moveActivityToDisplay()
+        // option would be a better choice here.
+        if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) {
+            Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId()
+                    + " to main stack for VR");
+            moveTaskToStack(r.getTask().taskId, FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */);
+        }
         mHandler.sendMessage(
                 mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
     }
index 06f1a50..995ac37 100644 (file)
@@ -948,8 +948,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
         // the user leaves that mode.
         mLastReportedMultiWindowMode = !task.mFullscreen;
         mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID);
-
-        onOverrideConfigurationSent();
     }
 
     void removeWindowContainer() {
@@ -2220,15 +2218,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
      * a new merged configuration is sent to the client for this activity.
      */
     void setLastReportedConfiguration(@NonNull MergedConfiguration config) {
-        mLastReportedConfiguration.setTo(config);
+        setLastReportedConfiguration(config.getGlobalConfiguration(),
+            config.getOverrideConfiguration());
     }
 
-    /** Call when override config was sent to the Window Manager to update internal records. */
-    // TODO(b/36505427): Why do we set last reported based on sending the config to WM? Seems like
-    // we should only set this when we actually report to the activity which is what the method
-    // setLastReportedMergedOverrideConfiguration() does. Investigate if this is really needed.
-    void onOverrideConfigurationSent() {
-        mLastReportedConfiguration.setOverrideConfiguration(getMergedOverrideConfiguration());
+    void setLastReportedConfiguration(Configuration global, Configuration override) {
+        mLastReportedConfiguration.setConfiguration(global, override);
     }
 
     @Override
@@ -2242,9 +2237,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
             return;
         }
         mWindowContainerController.onOverrideConfigurationChanged(newConfig, mBounds);
-        // TODO(b/36505427): Can we consolidate the call points of onOverrideConfigurationSent()
-        // to just use this method instead?
-        onOverrideConfigurationSent();
     }
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
@@ -2431,8 +2423,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
 
         // Update last reported values.
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
-        mLastReportedConfiguration.setConfiguration(service.getGlobalConfiguration(),
-                newMergedOverrideConfig);
+
+        setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
 
         if (changes == 0 && !forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
index 88d8944..261797e 100644 (file)
@@ -96,6 +96,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -1293,7 +1294,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
             // created controller for the activity we are starting yet.
             mWindowContainerController.positionChildAt(appController, index);
         }
-        r.onOverrideConfigurationSent();
 
         // Make sure the list of display UID whitelists is updated
         // now that this record is in a new task.
@@ -1580,8 +1580,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
         // A task can not be docked even if it is considered resizeable because it only supports
         // picture-in-picture mode but has a non-resizeable resizeMode
         return mService.mSupportsSplitScreenMultiWindow
-                && isResizeable(false /* checkSupportsPip */)
-                && !ActivityInfo.isPreserveOrientationMode(mResizeMode);
+                && (mService.mForceResizableActivities
+                        || (isResizeable(false /* checkSupportsPip */)
+                                && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
     }
 
     /**
index 83bacc2..5927b2f 100644 (file)
@@ -19,6 +19,7 @@ package com.android.server.locksettings;
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
@@ -77,6 +78,7 @@ import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 
@@ -559,6 +561,10 @@ public class LockSettingsService extends ILockSettings.Stub {
 
     @Override // binder interface
     public void systemReady() {
+        if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
+        }
+        checkWritePermission(UserHandle.USER_SYSTEM);
         migrateOldData();
         try {
             getGateKeeperService();
@@ -805,6 +811,13 @@ public class LockSettingsService extends ILockSettings.Stub {
         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
     }
 
+    private final void checkPasswordHavePermission(int userId) {
+        if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
+            EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), "");  // SafetyNet
+        }
+        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
+    }
+
     private final void checkReadPermission(String requestedKey, int userId) {
         final int callingUid = Binder.getCallingUid();
 
@@ -934,6 +947,7 @@ public class LockSettingsService extends ILockSettings.Stub {
 
     @Override
     public boolean havePassword(int userId) throws RemoteException {
+        checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 long handle = getSyntheticPasswordHandleLocked(userId);
@@ -947,6 +961,7 @@ public class LockSettingsService extends ILockSettings.Stub {
 
     @Override
     public boolean havePattern(int userId) throws RemoteException {
+        checkPasswordHavePermission(userId);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 long handle = getSyntheticPasswordHandleLocked(userId);
index 0072ba4..f88a074 100644 (file)
@@ -3046,9 +3046,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
                 if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
                         != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
-                    if (isUidIdle(uid)) {
-                        updateRuleForAppIdleUL(uid);
-                    }
+                    updateRuleForAppIdleUL(uid);
                     if (mDeviceIdleMode) {
                         updateRuleForDeviceIdleUL(uid);
                     }
index beaddb4..d5d0250 100644 (file)
@@ -877,6 +877,7 @@ abstract public class ManagedServices {
 
                 @Override
                 public void onServiceDisconnected(ComponentName name) {
+                    mServicesBinding.remove(servicesBindingTag);
                     Slog.v(TAG, getCaption() + " connection lost: " + name);
                 }
             };
@@ -889,6 +890,7 @@ abstract public class ManagedServices {
                 return;
             }
         } catch (SecurityException ex) {
+            mServicesBinding.remove(servicesBindingTag);
             Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
         }
     }
index 28acd9a..f60d923 100644 (file)
@@ -804,6 +804,7 @@ public class NotificationManagerService extends SystemService {
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
                 mZenModeHelper.updateDefaultZenRules();
+                mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
             }
         }
     };
@@ -3104,7 +3105,7 @@ public class NotificationManagerService extends SystemService {
             }
         }
         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
-                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
+                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
         }
     }
@@ -3449,7 +3450,8 @@ public class NotificationManagerService extends SystemService {
                 user, null, System.currentTimeMillis());
         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
 
-        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
+        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
+                r.sbn.getOverrideGroupKey() != null)) {
             return;
         }
 
@@ -3504,7 +3506,7 @@ public class NotificationManagerService extends SystemService {
      * Has side effects.
      */
     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
-            NotificationRecord r) {
+            NotificationRecord r, boolean isAutogroup) {
         final String pkg = r.sbn.getPackageName();
         final String dialerPackage =
                 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
@@ -3528,7 +3530,8 @@ public class NotificationManagerService extends SystemService {
 
                 // rate limit updates that aren't completed progress notifications
                 if (mNotificationsByKey.get(r.sbn.getKey()) != null
-                        && !r.getNotification().hasCompletedProgress()) {
+                        && !r.getNotification().hasCompletedProgress()
+                        && !isAutogroup) {
 
                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
@@ -3536,7 +3539,7 @@ public class NotificationManagerService extends SystemService {
                         final long now = SystemClock.elapsedRealtime();
                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
-                                    + ". Shedding events. package=" + pkg);
+                                    + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
                             mLastOverRateLogTime = now;
                         }
                         return false;
index 9622a24..3386fe8 100644 (file)
@@ -1073,6 +1073,22 @@ public class RankingHelper implements RankingConfig {
         }
     }
 
+    protected void onLocaleChanged(Context context, int userId) {
+        synchronized (mRecords) {
+            int N = mRecords.size();
+            for (int i = 0; i < N; i++) {
+                Record record = mRecords.valueAt(i);
+                if (UserHandle.getUserId(record.uid) == userId) {
+                    if (record.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+                        record.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(
+                                context.getResources().getString(
+                                        R.string.default_notification_channel_label));
+                    }
+                }
+            }
+        }
+    }
+
     public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
             int[] uidList) {
         if (pkgList == null || pkgList.length == 0) {
index d99408f..56835f6 100644 (file)
@@ -4867,7 +4867,7 @@ final class Settings {
             pw.print(" enabled=");
             pw.print(ps.getEnabled(user.id));
             pw.print(" instant=");
-            pw.println(ps.getInstantApp(user.id));
+            pw.print(ps.getInstantApp(user.id));
             pw.print(" virtual=");
             pw.println(ps.getVirtulalPreload(user.id));
 
index 1ca98ac..f142ff6 100644 (file)
@@ -632,9 +632,12 @@ public class AppWindowContainerController
                 mContainer.startingSurface = null;
                 mContainer.startingWindow = null;
                 mContainer.startingDisplayed = false;
-                if (surface == null && DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
-                            + "remove");
+                if (surface == null) {
+                    if (DEBUG_STARTING_WINDOW) {
+                        Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
+                                + "remove");
+                    }
+                    return;
                 }
             } else {
                 if (DEBUG_STARTING_WINDOW) {
index 801479b..65bf330 100644 (file)
@@ -46,6 +46,7 @@ import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.media.AudioAttributes;
 import android.net.Uri;
@@ -78,6 +79,7 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -127,6 +129,8 @@ public class RankingHelperTest extends NotificationTestCase {
         when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
         when(mContext.getResources()).thenReturn(
                 InstrumentationRegistry.getContext().getResources());
+        when(mContext.getContentResolver()).thenReturn(
+                InstrumentationRegistry.getContext().getContentResolver());
         when(mContext.getPackageManager()).thenReturn(mPm);
         when(mContext.getApplicationInfo()).thenReturn(legacy);
         // most tests assume badging is enabled
@@ -1366,4 +1370,22 @@ public class RankingHelperTest extends NotificationTestCase {
         assertFalse(mHelper.badgingEnabled(USER));
         assertTrue(mHelper.badgingEnabled(USER2));
     }
+
+    @Test
+    public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
+        String newLabel = "bananas!";
+        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false);
+        assertFalse(newLabel.equals(defaultChannel.getName()));
+
+        Resources res = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(res);
+        when(res.getString(com.android.internal.R.string.default_notification_channel_label))
+                .thenReturn(newLabel);
+
+        mHelper.onLocaleChanged(mContext, USER.getIdentifier());
+
+        assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
+                NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
+    }
 }
index c1289d3..e13bd61 100644 (file)
@@ -1089,12 +1089,17 @@ public final class Call {
          * @return A string containing text sent by the remote user, or {@code null} if the
          * conversation has been terminated or if there was an error while reading.
          */
-        public String read() throws IOException {
-            int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
-            if (numRead < 0) {
+        public String read() {
+            try {
+                int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
+            } catch (IOException e) {
+                Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
                 return null;
             }
-            return new String(mReadBuffer, 0, numRead);
         }
 
         /**
@@ -1105,7 +1110,11 @@ public final class Call {
          */
         public String readImmediately() throws IOException {
             if (mReceiveStream.ready()) {
-                return read();
+                int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
             } else {
                 return null;
             }
index 7f9de0d..735f09b 100644 (file)
@@ -567,20 +567,27 @@ public class CarrierConfigManager {
             "carrier_data_call_retry_config_strings";
 
     /**
-     * Delay between trying APN from the pool
+     * Delay in milliseconds between trying APN from the pool
      * @hide
      */
     public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
             "carrier_data_call_apn_delay_default_long";
 
     /**
-     * Faster delay between trying APN from the pool
+     * Faster delay in milliseconds between trying APN from the pool
      * @hide
      */
     public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
             "carrier_data_call_apn_delay_faster_long";
 
     /**
+     * Delay in milliseconds for retrying APN after disconnect
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG =
+            "carrier_data_call_apn_retry_after_disconnect_long";
+
+    /**
      * Data call setup permanent failure causes by the carrier
      */
     public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -1166,8 +1173,6 @@ public class CarrierConfigManager {
     /** @hide */
     public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
     /** @hide */
-    public static final int IMSI_ENCRYPTION_DAYS_TIME_DISABLED = -1;
-    /** @hide */
     public static final int CDMA_ROAMING_MODE_ANY = 2;
     /**
      * Boolean indicating if support is provided for directly dialing FDN number from FDN list.
@@ -1526,14 +1531,15 @@ public class CarrierConfigManager {
     public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
 
     /**
-     * Time in days, after which the key will expire, and a new key will need to be downloaded.
-     * default value is {@link IMSI_ENCRYPTION_DAYS_TIME_DISABLED}, and indicates that IMSI
-     * encryption is not enabled by default for a carrier. Value of 0 indicates that the key
-     * does not expire.
+     * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
+     * 0 indicates that neither EPDG or WLAN is enabled.
+     * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled.
+     * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled.
+     * 3 indicates that both are enabled.
      * @hide
      */
-    public static final String IMSI_KEY_EXPIRATION_DAYS_TIME_INT =
-            "imsi_key_expiration_days_time_int";
+    public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
+
 
     /**
      * Key identifying if the CDMA Caller ID presentation and suppression MMI codes
@@ -1645,6 +1651,7 @@ public class CarrierConfigManager {
                 "others:max_retries=3, 5000, 5000, 5000"});
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
+        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 10000);
         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
         sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
         sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
@@ -1806,7 +1813,7 @@ public class CarrierConfigManager {
         sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
         sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
-        sDefaults.putInt(IMSI_KEY_EXPIRATION_DAYS_TIME_INT, IMSI_ENCRYPTION_DAYS_TIME_DISABLED);
+        sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
         sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
         sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
                 false);
index 5fb83ab..e448fb2 100644 (file)
@@ -795,34 +795,57 @@ public class ServiceState implements Parcelable {
         return rtString;
     }
 
+    /**
+     * Convert RIL Service State to String
+     *
+     * @param serviceState
+     * @return String representation of the ServiceState
+     *
+     * @hide
+     */
+    public static String rilServiceStateToString(int serviceState) {
+        switch(serviceState) {
+            case STATE_IN_SERVICE:
+                return "IN_SERVICE";
+            case STATE_OUT_OF_SERVICE:
+                return "OUT_OF_SERVICE";
+            case STATE_EMERGENCY_ONLY:
+                return "EMERGENCY_ONLY";
+            case STATE_POWER_OFF:
+                return "POWER_OFF";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     @Override
     public String toString() {
-        String radioTechnology = rilRadioTechnologyToString(mRilVoiceRadioTechnology);
-        String dataRadioTechnology = rilRadioTechnologyToString(mRilDataRadioTechnology);
-
-        return (mVoiceRegState + " " + mDataRegState
-                + " "
-                + "voice " + getRoamingLogString(mVoiceRoamingType)
-                + " "
-                + "data " + getRoamingLogString(mDataRoamingType)
-                + " " + mVoiceOperatorAlphaLong
-                + " " + mVoiceOperatorAlphaShort
-                + " " + mVoiceOperatorNumeric
-                + " " + mDataOperatorAlphaLong
-                + " " + mDataOperatorAlphaShort
-                + " " + mDataOperatorNumeric
-                + " " + (mIsManualNetworkSelection ? "(manual)" : "")
-                + " " + radioTechnology
-                + " " + dataRadioTechnology
-                + " " + (mCssIndicator ? "CSS supported" : "CSS not supported")
-                + " " + mNetworkId
-                + " " + mSystemId
-                + " RoamInd=" + mCdmaRoamingIndicator
-                + " DefRoamInd=" + mCdmaDefaultRoamingIndicator
-                + " EmergOnly=" + mIsEmergencyOnly
-                + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration
-                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation
-                + " mLteEarfcnRsrpBoost=" + mLteEarfcnRsrpBoost);
+        return new StringBuilder().append("{mVoiceRegState=").append(mVoiceRegState)
+            .append("(" + rilServiceStateToString(mVoiceRegState) + ")")
+            .append(", mDataRegState=").append(mDataRegState)
+            .append("(" + rilServiceStateToString(mDataRegState) + ")")
+            .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
+            .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
+            .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
+            .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
+            .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
+            .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
+            .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
+            .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
+            .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")")
+            .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")")
+            .append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported")
+            .append(", mNetworkId=").append(mNetworkId)
+            .append(", mSystemId=").append(mSystemId)
+            .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
+            .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
+            .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
+            .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
+            .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+            .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
+            .append("}").toString();
     }
 
     private void setNullState(int state) {
index 6a9d00e..5f4283f 100644 (file)
@@ -137,7 +137,7 @@ public class TelephonyManager {
 
 
     /** @hide */
-    static public final int KEY_TYPE_EPDDG = 1;
+    static public final int KEY_TYPE_EPDG = 1;
 
     /** @hide */
     static public final int KEY_TYPE_WLAN = 2;
@@ -2373,31 +2373,73 @@ public class TelephonyManager {
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      * @param keyType whether the key is being used for wlan or epdg. Valid key types are
-     *        {@link TelephonyManager#KEY_TYPE_EPDDG} or
+     *        {@link TelephonyManager#KEY_TYPE_EPDG} or
      *        {@link TelephonyManager#KEY_TYPE_WLAN}.
      * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
      *         IMSI and IMPI. This includes the public key and the key identifier. This information
-     *         will be stored in the device keystore.
+     *         will be stored in the device keystore. The system will return a null when no key was
+     *         found, and the carrier does not require a key. The system will throw the following
+     *         exceptions:
+     *         1. IllegalArgumentException when an invalid key is sent.
+     *         2. RuntimeException if the key is required but not found; and also if there was an
+     *         internal exception.
      * @hide
      */
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
-            if (info == null) return null;
+            if (info == null) {
+                throw new RuntimeException("IMSI error: Subscriber Info is null");
+            }
             int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
-            if (keyType != KEY_TYPE_EPDDG && keyType != KEY_TYPE_WLAN) {
-                throw new IllegalArgumentException("Invalid key type");
+            if (keyType != KEY_TYPE_EPDG && keyType != KEY_TYPE_WLAN) {
+                throw new IllegalArgumentException("IMSI error: Invalid key type");
+            }
+            ImsiEncryptionInfo imsiEncryptionInfo = info.getCarrierInfoForImsiEncryption(
+                    subId, keyType, mContext.getOpPackageName());
+            if (imsiEncryptionInfo  == null
+                    && isImsiEncryptionRequired(subId, keyType)) {
+                Rlog.e(TAG, "IMSI error: key is required but not found");
+                throw new RuntimeException("IMSI error: key is required but not found");
             }
-            return info.getCarrierInfoForImsiEncryption(subId, keyType,
-                    mContext.getOpPackageName());
+            return imsiEncryptionInfo;
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException", ex);
-            return null;
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
+            throw new RuntimeException("IMSI error: Remote Exception");
         } catch (NullPointerException ex) {
             // This could happen before phone restarts due to crashing
-            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException", ex);
-            return null;
+            Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
+            throw new RuntimeException("IMSI error: Null Pointer exception");
+        }
+    }
+
+   /**
+     * @param keyAvailability bitmask that defines the availabilty of keys for a type.
+     * @param keyType the key type which is being checked. (WLAN, EPDG)
+     * @return true if the digit at position keyType is 1, else false.
+     * @hide
+     */
+    private static boolean isKeyEnabled(int keyAvailability, int keyType) {
+        int returnValue = (keyAvailability >> (keyType - 1)) & 1;
+        return (returnValue == 1) ? true : false;
+    }
+
+    /**
+     * If Carrier requires Imsi to be encrypted.
+     * @hide
+     */
+    private boolean isImsiEncryptionRequired(int subId, int keyType) {
+        CarrierConfigManager configManager =
+                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager == null) {
+            return false;
+        }
+        PersistableBundle pb = configManager.getConfigForSubId(subId);
+        if (pb == null) {
+            return false;
         }
+        int keyAvailability = pb.getInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT);
+        return isKeyEnabled(keyAvailability, keyType);
     }
 
     /**
 
 package android.net;
 
-import android.net.IpPrefix;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
 import java.net.InetAddress;
 import java.util.Random;
-import junit.framework.TestCase;
 
-import static android.test.MoreAsserts.assertNotEqual;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-public class IpPrefixTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpPrefixTest {
 
     private static InetAddress Address(String addr) {
         return InetAddress.parseNumericAddress(addr);
@@ -42,7 +51,7 @@ public class IpPrefixTest extends TestCase {
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
     };
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         IpPrefix p;
         try {
@@ -103,6 +112,7 @@ public class IpPrefixTest extends TestCase {
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testTruncation() {
         IpPrefix p;
 
@@ -170,7 +180,7 @@ public class IpPrefixTest extends TestCase {
         assertFalse(o2.equals(o1));
     }
 
-    @SmallTest
+    @Test
     public void testEquals() {
         IpPrefix p1, p2;
 
@@ -212,7 +222,7 @@ public class IpPrefixTest extends TestCase {
         assertAreNotEqual(p1, p2);
     }
 
-    @SmallTest
+    @Test
     public void testContains() {
         IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
         assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
@@ -240,7 +250,7 @@ public class IpPrefixTest extends TestCase {
         assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
     }
 
-    @SmallTest
+    @Test
     public void testHashCode() {
         IpPrefix p = new IpPrefix(new byte[4], 0);
         Random random = new Random();
@@ -261,12 +271,12 @@ public class IpPrefixTest extends TestCase {
               assertEquals(p.hashCode(), oldP.hashCode());
             }
             if (p.hashCode() != oldP.hashCode()) {
-              assertNotEqual(p, oldP);
+              assertNotEquals(p, oldP);
             }
         }
     }
 
-    @SmallTest
+    @Test
     public void testHashCodeIsNotConstant() {
         IpPrefix[] prefixes = {
             new IpPrefix("2001:db8:f00::ace:d00d/127"),
@@ -276,12 +286,12 @@ public class IpPrefixTest extends TestCase {
         };
         for (int i = 0; i < prefixes.length; i++) {
           for (int j = i + 1; j < prefixes.length; j++) {
-            assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+            assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
           }
         }
     }
 
-    @SmallTest
+    @Test
     public void testMappedAddressesAreBroken() {
         // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
         // we are unable to comprehend that.
@@ -318,13 +328,16 @@ public class IpPrefixTest extends TestCase {
       assertEquals(p, p2);
     }
 
+    @Test
     public void testParceling() {
         IpPrefix p;
 
         p = new IpPrefix("2001:4860:db8::/64");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv6());
 
         p = new IpPrefix("192.0.2.0/25");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv4());
     }
 }
 
 package android.net;
 
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
+import static android.system.OsConstants.IFA_F_TEMPORARY;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -27,44 +44,35 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import android.net.LinkAddress;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
-import static android.test.MoreAsserts.assertNotEqual;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TEMPORARY;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-/**
- * Tests for {@link LinkAddress}.
- */
-public class LinkAddressTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkAddressTest {
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
     private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
     private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
 
+    @Test
     public void testConstants() {
         // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
-        assertNotEqual(0, RT_SCOPE_HOST);
-        assertNotEqual(0, RT_SCOPE_LINK);
-        assertNotEqual(0, RT_SCOPE_SITE);
+        assertNotEquals(0, RT_SCOPE_HOST);
+        assertNotEquals(0, RT_SCOPE_LINK);
+        assertNotEquals(0, RT_SCOPE_SITE);
 
-        assertNotEqual(0, IFA_F_DEPRECATED);
-        assertNotEqual(0, IFA_F_PERMANENT);
-        assertNotEqual(0, IFA_F_TENTATIVE);
+        assertNotEquals(0, IFA_F_DEPRECATED);
+        assertNotEquals(0, IFA_F_PERMANENT);
+        assertNotEquals(0, IFA_F_TENTATIVE);
     }
 
+    @Test
     public void testConstructors() throws SocketException {
         LinkAddress address;
 
@@ -74,12 +82,14 @@ public class LinkAddressTest extends AndroidTestCase {
         assertEquals(25, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv4());
 
         address = new LinkAddress(V6_ADDRESS, 127);
         assertEquals(V6_ADDRESS, address.getAddress());
         assertEquals(127, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv6());
 
         // Nonsensical flags/scopes or combinations thereof are acceptable.
         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
@@ -87,12 +97,14 @@ public class LinkAddressTest extends AndroidTestCase {
         assertEquals(64, address.getPrefixLength());
         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
         assertEquals(RT_SCOPE_LINK, address.getScope());
+        assertTrue(address.isIPv6());
 
         address = new LinkAddress(V4 + "/23", 123, 456);
         assertEquals(V4_ADDRESS, address.getAddress());
         assertEquals(23, address.getPrefixLength());
         assertEquals(123, address.getFlags());
         assertEquals(456, address.getScope());
+        assertTrue(address.isIPv4());
 
         // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
         List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
@@ -174,6 +186,7 @@ public class LinkAddressTest extends AndroidTestCase {
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testAddressScopes() {
         assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
         assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
@@ -216,6 +229,7 @@ public class LinkAddressTest extends AndroidTestCase {
         assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
     }
 
+    @Test
     public void testEqualsAndSameAddressAs() {
         LinkAddress l1, l2, l3;
 
@@ -293,26 +307,17 @@ public class LinkAddressTest extends AndroidTestCase {
         assertIsSameAddressAs(l1, l2);
     }
 
+    @Test
     public void testHashCode() {
-        LinkAddress l;
-
-        l = new LinkAddress(V4_ADDRESS, 23);
-        assertEquals(-982787, l.hashCode());
-
-        l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
-        assertEquals(-971865, l.hashCode());
-
-        l = new LinkAddress(V4_ADDRESS, 27);
-        assertEquals(-982743, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 64);
-        assertEquals(1076522926, l.hashCode());
+        LinkAddress l1, l2;
 
-        l = new LinkAddress(V6_ADDRESS, 128);
-        assertEquals(1076523630, l.hashCode());
+        l1 = new LinkAddress(V4_ADDRESS, 23);
+        l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
 
-        l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
-        assertEquals(1076524846, l.hashCode());
+        l1 = new LinkAddress(V6_ADDRESS, 128);
+        l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
     }
 
     private LinkAddress passThroughParcel(LinkAddress l) {
@@ -334,6 +339,7 @@ public class LinkAddressTest extends AndroidTestCase {
       assertEquals(l, l2);
     }
 
+    @Test
     public void testParceling() {
         LinkAddress l;
 
@@ -352,6 +358,7 @@ public class LinkAddressTest extends AndroidTestCase {
         assertFalse(msg, l.isGlobalPreferred());
     }
 
+    @Test
     public void testIsGlobalPreferred() {
         LinkAddress l;
 
index ac5df05..dc5ba0c 100644 (file)
@@ -1,5 +1,6 @@
 package android.net.wifi;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
@@ -313,6 +314,7 @@ public class RttManager {
              };
     }
 
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public RttCapabilities getRttCapabilities() {
         synchronized (mCapabilitiesLock) {
             if (mRttCapabilities == null) {
@@ -925,6 +927,51 @@ public class RttManager {
         public void onAborted();
     }
 
+    /**
+     * A parcelable that contains rtt client information.
+     *
+     * @hide
+     */
+    public static class RttClient implements Parcelable {
+        // Package name of RttClient.
+        private final String mPackageName;
+
+        public RttClient(String packageName) {
+            mPackageName = packageName;
+        }
+
+        protected RttClient(Parcel in) {
+            mPackageName = in.readString();
+        }
+
+        public static final Creator<RttManager.RttClient> CREATOR =
+                new Creator<RttManager.RttClient>() {
+            @Override
+            public RttManager.RttClient createFromParcel(Parcel in) {
+                return new RttManager.RttClient(in);
+            }
+
+            @Override
+            public RttManager.RttClient[] newArray(int size) {
+                return new RttManager.RttClient[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int i) {
+            parcel.writeString(mPackageName);
+        }
+
+        public String getPackageName() {
+            return mPackageName;
+        }
+    }
+
     private boolean rttParamSanity(RttParams params, int index) {
         if (mRttCapabilities == null) {
             if(getRttCapabilities() == null) {
@@ -1236,7 +1283,8 @@ public class RttManager {
         mAsyncChannel.connectSync(mContext, handler, messenger);
         // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
         // synchronously, which causes RttService to receive the wrong replyTo value.
-        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION,
+                new RttClient(context.getPackageName()));
         mAsyncChannel.sendMessage(CMD_OP_REG_BINDER, key[0]);
     }