Merge "Merge "Themes: Apply themes to system_server safely" into oc-dev am: a52fc49845 am: b188c93a45"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e49aad2..d1d462c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -221,6 +221,7 @@
private long mNetworkBlockSeq = INVALID_PROC_STATE_SEQ;
private ContextImpl mSystemContext;
+ private ContextImpl mSystemUiContext;
static volatile IPackageManager sPackageManager;
@@ -2190,9 +2191,19 @@
}
}
+ 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 @@
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 @@
// 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 461f9cc..a6838f8b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1352,7 +1352,7 @@
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 @@
"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 f95fa99..c5e970f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2217,6 +2217,18 @@
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 b42df5e..489a0f0 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -984,7 +984,7 @@
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 aa2adc7..a585720 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4642,4 +4642,18 @@
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 421d5a6..c105b12 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 @@
}
/**
+ * 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 81ba7a7..4c747a1 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 @@
@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 @@
} 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 @@
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 @@
} 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 @@
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 @@
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 ActivityManagerService(Injector injector) {
mInjector = injector;
mContext = mInjector.getContext();
+ mUiContext = null;
GL_ES_VERSION = 0;
mActivityStarter = null;
mAppErrors = null;
@@ -2762,8 +2769,10 @@
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 @@
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 @@
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 21c131c..ba72dcf 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 @@
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 5f7f67a..347a357 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 @@
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 9c4e700..a60dae7 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 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 841e2a1..864e83e 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 @@
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 @@
* 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 @@
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 @@
* 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 @@
* 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 212bd61..218d218 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 @@
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 @@
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 1691d14..f1796de 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.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 @@
// 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 3f197b7..1312c8f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -475,6 +475,9 @@
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
+
+ final Context systemUiContext = activityThread.getSystemUiContext();
+ systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
/**