diff options
14 files changed, 119 insertions, 33 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e49aad2cd607..d1d462c2fbe8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -221,6 +221,7 @@ public final class ActivityThread {      private long mNetworkBlockSeq = INVALID_PROC_STATE_SEQ;      private ContextImpl mSystemContext; +    private ContextImpl mSystemUiContext;      static volatile IPackageManager sPackageManager; @@ -2190,9 +2191,19 @@ public final class ActivityThread {          }      } +    public ContextImpl getSystemUiContext() { +        synchronized (this) { +            if (mSystemUiContext == null) { +                mSystemUiContext = ContextImpl.createSystemUiContext(this); +            } +            return mSystemUiContext; +        } +    } +      public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {          synchronized (this) {              getSystemContext().installSystemApplicationInfo(info, classLoader); +            getSystemUiContext().installSystemApplicationInfo(info, classLoader);              // give ourselves a default profiler              mProfiler = new Profiler(); @@ -5031,6 +5042,11 @@ public final class ActivityThread {              if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {                  systemTheme.rebase();              } + +            final Theme systemUiTheme = getSystemUiContext().getTheme(); +            if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { +                systemUiTheme.rebase(); +            }          }          ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); @@ -5086,9 +5102,10 @@ public final class ActivityThread {          // Trigger a regular Configuration change event, only with a different assetsSeq number          // so that we actually call through to all components. +        // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to +        // store configurations per-process.          Configuration newConfig = new Configuration(); -        newConfig.unset(); -        newConfig.assetsSeq = mConfiguration.assetsSeq + 1; +        newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;          handleConfigurationChanged(newConfig, null);          // Schedule all activities to reload diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 461f9cc35125..a6838f8bbf0a 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1352,7 +1352,7 @@ public class ApplicationPackageManager extends PackageManager {      public Resources getResourcesForApplication(@NonNull ApplicationInfo app)              throws NameNotFoundException {          if (app.packageName.equals("system")) { -            return mContext.mMainThread.getSystemContext().getResources(); +            return mContext.mMainThread.getSystemUiContext().getResources();          }          final boolean sameUid = (app.uid == Process.myUid());          final Resources r = mContext.mMainThread.getTopLevelResources( @@ -1383,7 +1383,7 @@ public class ApplicationPackageManager extends PackageManager {                      "Call does not support special user #" + userId);          }          if ("system".equals(appPackageName)) { -            return mContext.mMainThread.getSystemContext().getResources(); +            return mContext.mMainThread.getSystemUiContext().getResources();          }          try {              ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, sDefaultFlags, userId); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index f95fa990b79e..c5e970f99c1f 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2217,6 +2217,18 @@ class ContextImpl extends Context {          return context;      } +    /** +     * System Context to be used for UI. This Context has resources that can be themed. +     */ +    static ContextImpl createSystemUiContext(ActivityThread mainThread) { +        LoadedApk packageInfo = new LoadedApk(mainThread); +        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, +                null); +        context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null, +                packageInfo.getCompatibilityInfo())); +        return context; +    } +      static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {          if (packageInfo == null) throw new IllegalArgumentException("packageInfo");          ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index b42df5e2e0fb..489a0f0975ae 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -984,7 +984,7 @@ public class ResourcesManager {                  final ResourcesKey key = mResourceImpls.keyAt(i);                  final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);                  final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; -                if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) { +                if (impl != null && (key.mResDir == null || key.mResDir.equals(baseCodePath))) {                      updatedResourceKeys.put(impl, new ResourcesKey(                              key.mResDir,                              key.mSplitResDirs, diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index aa2adc74bc88..a585720ab895 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4642,4 +4642,18 @@ public abstract class Context {      public Handler getMainThreadHandler() {          throw new RuntimeException("Not implemented. Must override in a subclass.");      } + +    /** +     * Throws an exception if the Context is using system resources, +     * which are non-runtime-overlay-themable and may show inconsistent UI. +     * @hide +     */ +    public void assertRuntimeOverlayThemable() { +        // Resources.getSystem() is a singleton and the only Resources not managed by +        // ResourcesManager; therefore Resources.getSystem() is not themable. +        if (getResources() == Resources.getSystem()) { +            throw new IllegalArgumentException("Non-UI context used to display UI; " +                    + "get a UI context from ActivityThread#getSystemUiContext()"); +        } +    }  } diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 421d5a6ab964..c105b1244e74 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -16,6 +16,7 @@  package com.android.server; +import android.app.ActivityThread;  import android.content.Context;  import android.os.IBinder;  import android.os.ServiceManager; @@ -104,6 +105,16 @@ public abstract class SystemService {      }      /** +     * Get the system UI context. This context is to be used for displaying UI. It is themable, +     * which means resources can be overridden at runtime. Do not use to retrieve properties that +     * configure the behavior of the device that is not UX related. +     */ +    public final Context getUiContext() { +        // This has already been set up by the time any SystemServices are created. +        return ActivityThread.currentActivityThread().getSystemUiContext(); +    } + +    /**       * Returns true if the system is running in safe mode.       * TODO: we should define in which phase this becomes valid       */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 81ba7a733225..4c747a1c5433 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1350,7 +1350,13 @@ public class ActivityManagerService extends IActivityManager.Stub      @GuardedBy("this") boolean mLaunchWarningShown = false;      @GuardedBy("this") boolean mCheckedForSetup = false; -    Context mContext; +    final Context mContext; + +    /** +     * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can +     * change at runtime. Use mContext for non-UI purposes. +     */ +    final Context mUiContext;      /**       * The time at which we will allow normal application switches again, @@ -1852,7 +1858,7 @@ public class ActivityManagerService extends IActivityManager.Stub              } break;              case SHOW_FACTORY_ERROR_UI_MSG: {                  Dialog d = new FactoryErrorDialog( -                    mContext, msg.getData().getCharSequence("msg")); +                        mUiContext, msg.getData().getCharSequence("msg"));                  d.show();                  ensureBootCompleted();              } break; @@ -1863,7 +1869,7 @@ public class ActivityManagerService extends IActivityManager.Stub                          if (!app.waitedForDebugger) {                              Dialog d = new AppWaitingForDebuggerDialog(                                      ActivityManagerService.this, -                                    mContext, app); +                                    mUiContext, app);                              app.waitDialog = d;                              app.waitedForDebugger = true;                              d.show(); @@ -1878,24 +1884,24 @@ public class ActivityManagerService extends IActivityManager.Stub              } break;              case SHOW_UID_ERROR_UI_MSG: {                  if (mShowDialogs) { -                    AlertDialog d = new BaseErrorDialog(mContext); +                    AlertDialog d = new BaseErrorDialog(mUiContext);                      d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);                      d.setCancelable(false); -                    d.setTitle(mContext.getText(R.string.android_system_label)); -                    d.setMessage(mContext.getText(R.string.system_error_wipe_data)); -                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), +                    d.setTitle(mUiContext.getText(R.string.android_system_label)); +                    d.setMessage(mUiContext.getText(R.string.system_error_wipe_data)); +                    d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),                              obtainMessage(DISMISS_DIALOG_UI_MSG, d));                      d.show();                  }              } break;              case SHOW_FINGERPRINT_ERROR_UI_MSG: {                  if (mShowDialogs) { -                    AlertDialog d = new BaseErrorDialog(mContext); +                    AlertDialog d = new BaseErrorDialog(mUiContext);                      d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);                      d.setCancelable(false); -                    d.setTitle(mContext.getText(R.string.android_system_label)); -                    d.setMessage(mContext.getText(R.string.system_error_manufacturer)); -                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok), +                    d.setTitle(mUiContext.getText(R.string.android_system_label)); +                    d.setMessage(mUiContext.getText(R.string.system_error_manufacturer)); +                    d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),                              obtainMessage(DISMISS_DIALOG_UI_MSG, d));                      d.show();                  } @@ -1919,7 +1925,7 @@ public class ActivityManagerService extends IActivityManager.Stub                              if (mode == ActivityManager.COMPAT_MODE_DISABLED                                      || mode == ActivityManager.COMPAT_MODE_ENABLED) {                                  mCompatModeDialog = new CompatModeDialog( -                                        ActivityManagerService.this, mContext, +                                        ActivityManagerService.this, mUiContext,                                          ar.info.applicationInfo);                                  mCompatModeDialog.show();                              } @@ -1939,7 +1945,7 @@ public class ActivityManagerService extends IActivityManager.Stub                              ar.packageName)) {                          // TODO(multi-display): Show dialog on appropriate display.                          mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog( -                                ActivityManagerService.this, mContext, ar.info.applicationInfo); +                                ActivityManagerService.this, mUiContext, ar.info.applicationInfo);                          mUnsupportedDisplaySizeDialog.show();                      }                  } @@ -2731,6 +2737,7 @@ public class ActivityManagerService extends IActivityManager.Stub      public ActivityManagerService(Injector injector) {          mInjector = injector;          mContext = mInjector.getContext(); +        mUiContext = null;          GL_ES_VERSION = 0;          mActivityStarter = null;          mAppErrors = null; @@ -2762,8 +2769,10 @@ public class ActivityManagerService extends IActivityManager.Stub          LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);          mInjector = new Injector();          mContext = systemContext; +          mFactoryTest = FactoryTest.getMode();          mSystemThread = ActivityThread.currentActivityThread(); +        mUiContext = mSystemThread.getSystemUiContext();          Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); @@ -2806,7 +2815,7 @@ public class ActivityManagerService extends IActivityManager.Stub          mServices = new ActiveServices(this);          mProviderMap = new ProviderMap(this); -        mAppErrors = new AppErrors(mContext, this); +        mAppErrors = new AppErrors(mUiContext, this);          // TODO: Move creation of battery stats service outside of activity manager service.          File dataDir = Environment.getDataDirectory(); @@ -23893,7 +23902,7 @@ public class ActivityManagerService extends IActivityManager.Stub          final boolean updateFrameworkRes = packagesToUpdate.contains("android");          for (int i = mLruProcesses.size() - 1; i >= 0; i--) {              final ProcessRecord app = mLruProcesses.get(i); -            if (app.thread == null || app.pid == Process.myPid()) { +            if (app.thread == null) {                  continue;              } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 21c131c3616f..ba72dcf23c98 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -98,6 +98,7 @@ class AppErrors {      AppErrors(Context context, ActivityManagerService service) { +        context.assertRuntimeOverlayThemable();          mService = service;          mContext = context;      } diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index 5f7f67a8a5e8..347a357aae04 100644 --- a/services/core/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java @@ -34,6 +34,7 @@ class BaseErrorDialog extends AlertDialog {      public BaseErrorDialog(Context context) {          super(context, com.android.internal.R.style.Theme_Dialog_AppError); +        context.assertRuntimeOverlayThemable();          getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);          getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 9c4e700c87d3..a60dae7c7914 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2671,11 +2671,11 @@ public final class PowerManagerService extends SystemService              public void run() {                  synchronized (this) {                      if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) { -                        ShutdownThread.rebootSafeMode(mContext, confirm); +                        ShutdownThread.rebootSafeMode(getUiContext(), confirm);                      } else if (haltMode == HALT_MODE_REBOOT) { -                        ShutdownThread.reboot(mContext, reason, confirm); +                        ShutdownThread.reboot(getUiContext(), reason, confirm);                      } else { -                        ShutdownThread.shutdown(mContext, reason, confirm); +                        ShutdownThread.shutdown(getUiContext(), reason, confirm);                      }                  }              } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 841e2a158c4f..864e83ef1f86 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -79,7 +79,7 @@ public final class ShutdownThread extends Thread {      private static final int SHUTDOWN_VIBRATE_MS = 500;      // state tracking -    private static Object sIsStartedGuard = new Object(); +    private static final Object sIsStartedGuard = new Object();      private static boolean sIsStarted = false;      private static boolean mReboot; @@ -121,7 +121,8 @@ public final class ShutdownThread extends Thread {       * state etc.  Must be called from a Looper thread in which its UI       * is shown.       * -     * @param context Context used to display the shutdown progress dialog. +     * @param context Context used to display the shutdown progress dialog. This must be a context +     *                suitable for displaying UI (aka Themable).       * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.       * @param confirm true if user confirmation is needed before shutting down.       */ @@ -132,7 +133,11 @@ public final class ShutdownThread extends Thread {          shutdownInner(context, confirm);      } -    static void shutdownInner(final Context context, boolean confirm) { +    private static void shutdownInner(final Context context, boolean confirm) { +        // ShutdownThread is called from many places, so best to verify here that the context passed +        // in is themed. +        context.assertRuntimeOverlayThemable(); +          // ensure that only one thread is trying to power down.          // any additional calls are just returned          synchronized (sIsStartedGuard) { @@ -204,7 +209,8 @@ public final class ShutdownThread extends Thread {       * state etc.  Must be called from a Looper thread in which its UI       * is shown.       * -     * @param context Context used to display the shutdown progress dialog. +     * @param context Context used to display the shutdown progress dialog. This must be a context +     *                suitable for displaying UI (aka Themable).       * @param reason code to pass to the kernel (e.g. "recovery"), or null.       * @param confirm true if user confirmation is needed before shutting down.       */ @@ -220,7 +226,8 @@ public final class ShutdownThread extends Thread {       * Request a reboot into safe mode.  Must be called from a Looper thread in which its UI       * is shown.       * -     * @param context Context used to display the shutdown progress dialog. +     * @param context Context used to display the shutdown progress dialog. This must be a context +     *                suitable for displaying UI (aka Themable).       * @param confirm true if user confirmation is needed before shutting down.       */      public static void rebootSafeMode(final Context context, boolean confirm) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 212bd61dbc9a..218d21826d93 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -16,6 +16,7 @@  package com.android.server.statusbar; +import android.app.ActivityThread;  import android.app.StatusBarManager;  import android.content.ComponentName;  import android.content.Context; @@ -61,6 +62,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {      private static final boolean SPEW = false;      private final Context mContext; +      private final WindowManagerService mWindowManager;      private Handler mHandler = new Handler();      private NotificationDelegate mNotificationDelegate; @@ -777,10 +779,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub {          long identity = Binder.clearCallingIdentity();          try {              mHandler.post(() -> { +                // ShutdownThread displays UI, so give it a UI context. +                Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();                  if (safeMode) { -                    ShutdownThread.rebootSafeMode(mContext, false); +                    ShutdownThread.rebootSafeMode(uiContext, false);                  } else { -                    ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, false); +                    ShutdownThread.reboot(uiContext, PowerManager.SHUTDOWN_USER_REQUESTED, false);                  }              });          } finally { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1691d1408356..f1796de2d342 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -102,6 +102,7 @@ import android.annotation.Nullable;  import android.app.ActivityManager;  import android.app.ActivityManager.TaskSnapshot;  import android.app.ActivityManagerInternal; +import android.app.ActivityThread;  import android.app.AppOpsManager;  import android.app.IActivityManager;  import android.content.BroadcastReceiver; @@ -3196,19 +3197,25 @@ public class WindowManagerService extends IWindowManager.Stub      // Called by window manager policy.  Not exposed externally.      @Override      public void shutdown(boolean confirm) { -        ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); +        // Pass in the UI context, since ShutdownThread requires it (to show UI). +        ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), +                PowerManager.SHUTDOWN_USER_REQUESTED, confirm);      }      // Called by window manager policy.  Not exposed externally.      @Override      public void reboot(boolean confirm) { -        ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); +        // Pass in the UI context, since ShutdownThread requires it (to show UI). +        ShutdownThread.reboot(ActivityThread.currentActivityThread().getSystemUiContext(), +                PowerManager.SHUTDOWN_USER_REQUESTED, confirm);      }      // Called by window manager policy.  Not exposed externally.      @Override      public void rebootSafeMode(boolean confirm) { -        ShutdownThread.rebootSafeMode(mContext, confirm); +        // Pass in the UI context, since ShutdownThread requires it (to show UI). +        ShutdownThread.rebootSafeMode(ActivityThread.currentActivityThread().getSystemUiContext(), +                confirm);      }      public void setCurrentProfileIds(final int[] currentProfileIds) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3f197b7f3927..1312c8f55c48 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -475,6 +475,9 @@ public final class SystemServer {          ActivityThread activityThread = ActivityThread.systemMain();          mSystemContext = activityThread.getSystemContext();          mSystemContext.setTheme(DEFAULT_SYSTEM_THEME); + +        final Context systemUiContext = activityThread.getSystemUiContext(); +        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);      }      /**  |