diff options
Diffstat (limited to 'core/java/android/app')
-rw-r--r-- | core/java/android/app/ActivityManager.java | 23 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 185 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 10 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 21 |
4 files changed, 221 insertions, 18 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index fdf8921..0f20809 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1548,6 +1549,16 @@ public class ActivityManager { return new HashMap<String, Integer>(); } } + /** + * @hide + */ + public Configuration getConfiguration() { + try { + return ActivityManagerNative.getDefault().getConfiguration(); + } catch (RemoteException e) { + return null; + } + } /** * Returns the usage statistics of each installed package. @@ -1579,4 +1590,16 @@ public class ActivityManager { } } + /** + * @throws SecurityException Throws SecurityException if the caller does + * not hold the {@link android.Manifest.permission#CHANGE_CONFIGURATION} permission. + * + * @hide + */ + public void updateConfiguration(Configuration values) throws SecurityException { + try { + ActivityManagerNative.getDefault().updateConfiguration(values); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 0c761fc..a0ea99e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +17,28 @@ package android.app; +import com.android.internal.app.IAssetRedirectionManager; +import com.android.internal.os.BinderInternal; +import com.android.internal.os.RuntimeInit; +import com.android.internal.os.SamplingProfilerIntegration; + +import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; + import android.app.backup.BackupAgent; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentProvider; import android.content.Context; +import android.content.ContextWrapper; import android.content.IContentProvider; -import android.content.Intent; import android.content.IIntentReceiver; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; @@ -36,6 +46,8 @@ import android.content.pm.ServiceInfo; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.CustomTheme; +import android.content.res.PackageRedirectionMap; import android.content.res.Resources; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; @@ -47,6 +59,7 @@ import android.net.Proxy; import android.net.ProxyProperties; import android.opengl.GLUtils; import android.os.AsyncTask; +import android.net.Uri; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -60,6 +73,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; +import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.EventLog; @@ -68,6 +82,7 @@ import android.util.LogPrinter; import android.util.Slog; import android.view.Display; import android.view.HardwareRenderer; +import android.view.InflateException; import android.view.View; import android.view.ViewDebug; import android.view.ViewManager; @@ -76,12 +91,6 @@ import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import com.android.internal.os.BinderInternal; -import com.android.internal.os.RuntimeInit; -import com.android.internal.os.SamplingProfilerIntegration; - -import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; - import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -140,6 +149,7 @@ public final class ActivityThread { static ContextImpl mSystemContext = null; static IPackageManager sPackageManager; + static IAssetRedirectionManager sAssetRedirectionManager; final ApplicationThread mAppThread = new ApplicationThread(); final Looper mLooper = Looper.myLooper(); @@ -1355,12 +1365,14 @@ public final class ActivityThread { private static class ResourcesKey { final private String mResDir; final private float mScale; + final private boolean mIsThemeable; final private int mHash; - ResourcesKey(String resDir, float scale) { + ResourcesKey(String resDir, float scale, boolean isThemeable) { mResDir = resDir; mScale = scale; - mHash = mResDir.hashCode() << 2 + (int) (mScale * 2); + mIsThemeable = isThemeable; + mHash = mResDir.hashCode() << 3 + ((mIsThemeable ? 1 : 0) << 2) + (int) (mScale * 2); } @Override @@ -1374,7 +1386,8 @@ public final class ActivityThread { return false; } ResourcesKey peer = (ResourcesKey) obj; - return mResDir.equals(peer.mResDir) && mScale == peer.mScale; + return mResDir.equals(peer.mResDir) && mScale == peer.mScale && + mIsThemeable == peer.mIsThemeable; } } @@ -1405,6 +1418,18 @@ public final class ActivityThread { return sPackageManager; } + // NOTE: this method can return null if the SystemServer is still + // initializing (for example, of another SystemServer component is accessing + // a resources object) + public static IAssetRedirectionManager getAssetRedirectionManager() { + if (sAssetRedirectionManager != null) { + return sAssetRedirectionManager; + } + IBinder b = ServiceManager.getService("assetredirection"); + sAssetRedirectionManager = IAssetRedirectionManager.Stub.asInterface(b); + return sAssetRedirectionManager; + } + DisplayMetrics getDisplayMetricsLocked(CompatibilityInfo ci, boolean forceUpdate) { DisplayMetrics dm = mDisplayMetrics.get(ci); if (dm != null && !forceUpdate) { @@ -1454,7 +1479,7 @@ public final class ActivityThread { * null. */ Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) { - ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale); + ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale, compInfo.isThemeable); Resources r; synchronized (mPackages) { // Resources is app scale dependent. @@ -1480,10 +1505,23 @@ public final class ActivityThread { //} AssetManager assets = new AssetManager(); + assets.setThemeSupport(compInfo.isThemeable); if (assets.addAssetPath(resDir) == 0) { return null; } + /* Attach theme information to the resulting AssetManager when appropriate. */ + Configuration config = getConfiguration(); + if (compInfo.isThemeable && config != null) { + if (config.customTheme == null) { + config.customTheme = CustomTheme.getBootTheme(); + } + + if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) { + attachThemeAssets(assets, config.customTheme); + } + } + //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); DisplayMetrics metrics = getDisplayMetricsLocked(null, false); r = new Resources(assets, metrics, getConfiguration(), compInfo); @@ -1509,6 +1547,81 @@ public final class ActivityThread { } } + private void detachThemeAssets(AssetManager assets) { + String themePackageName = assets.getThemePackageName(); + int themeCookie = assets.getThemeCookie(); + if (!TextUtils.isEmpty(themePackageName) && themeCookie != 0) { + assets.detachThemePath(themePackageName, themeCookie); + assets.setThemePackageName(null); + assets.setThemeCookie(0); + assets.clearRedirections(); + } + } + + /** + * Attach the necessary theme asset paths and meta information to convert an + * AssetManager to being globally "theme-aware". + * + * @param assets + * @param theme + * @return true if the AssetManager is now theme-aware; false otherwise. + * This can fail, for example, if the theme package has been been + * removed and the theme manager has yet to revert formally back to + * the framework default. + */ + private boolean attachThemeAssets(AssetManager assets, CustomTheme theme) { + IAssetRedirectionManager rm = getAssetRedirectionManager(); + if (rm == null) { + return false; + } + PackageInfo pi = null; + try { + pi = getPackageManager().getPackageInfo(theme.getThemePackageName(), 0); + } catch (RemoteException e) { + } + if (pi != null && pi.applicationInfo != null && pi.themeInfos != null) { + String themeResDir = pi.applicationInfo.publicSourceDir; + int cookie = assets.attachThemePath(themeResDir); + if (cookie != 0) { + String themePackageName = theme.getThemePackageName(); + String themeId = theme.getThemeId(); + int N = assets.getBasePackageCount(); + for (int i = 0; i < N; i++) { + String packageName = assets.getBasePackageName(i); + int packageId = assets.getBasePackageId(i); + + /* + * For now, we only consider redirections coming from the + * framework or regular android packages. This excludes + * themes and other specialty APKs we are not aware of. + */ + if (packageId != 0x01 && packageId != 0x7f) { + continue; + } + + try { + PackageRedirectionMap map = rm.getPackageRedirectionMap(themePackageName, themeId, + packageName); + if (map != null) { + assets.addRedirections(map); + } + } catch (RemoteException e) { + Log.e(TAG, "Failure accessing package redirection map, removing theme support."); + assets.detachThemePath(themePackageName, cookie); + return false; + } + } + + assets.setThemePackageName(theme.getThemePackageName()); + assets.setThemeCookie(cookie); + return true; + } else { + Log.e(TAG, "Unable to attach theme assets at " + themeResDir); + } + } + return false; + } + /** * Creates the top level resources for the given package. */ @@ -1953,6 +2066,16 @@ public final class ActivityThread { } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { + if (e instanceof InflateException) { + Log.e(TAG, "Failed to inflate", e); + String pkg = null; + if (r.packageInfo != null && !TextUtils.isEmpty(r.packageInfo.getPackageName())) { + pkg = r.packageInfo.getPackageName(); + } + Intent intent = new Intent(Intent.ACTION_APP_LAUNCH_FAILURE, + (pkg != null)? Uri.fromParts("package", pkg, null) : null); + getSystemContext().sendBroadcast(intent); + } throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); @@ -3478,7 +3601,7 @@ public final class ActivityThread { } } - final boolean applyConfigurationToResourcesLocked(Configuration config, + final int applyConfigurationToResourcesLocked(Configuration config, CompatibilityInfo compat) { if (mResConfiguration == null) { mResConfiguration = new Configuration(); @@ -3486,7 +3609,7 @@ public final class ActivityThread { if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" + mResConfiguration.seq + ", newSeq=" + config.seq); - return false; + return 0; } int changes = mResConfiguration.updateFrom(config); DisplayMetrics dm = getDisplayMetricsLocked(null, true); @@ -3519,7 +3642,20 @@ public final class ActivityThread { if (r != null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + r + " config to: " + config); + boolean themeChanged = (changes & ActivityInfo.CONFIG_THEME_RESOURCE) != 0; + if (themeChanged) { + AssetManager am = r.getAssets(); + if (am.hasThemeSupport()) { + detachThemeAssets(am); + if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) { + attachThemeAssets(am, config.customTheme); + } + } + } r.updateConfiguration(config, dm, compat); + if (themeChanged) { + r.updateStringCache(); + } //Slog.i(TAG, "Updated app resources " + v.getKey() // + " " + r + ": " + r.getConfiguration()); } else { @@ -3528,7 +3664,7 @@ public final class ActivityThread { } } - return changes != 0; + return changes; } final Configuration applyCompatConfiguration() { @@ -3548,6 +3684,8 @@ public final class ActivityThread { ArrayList<ComponentCallbacks2> callbacks = null; + int diff = 0; + synchronized (mPackages) { if (mPendingConfiguration != null) { if (!mPendingConfiguration.isOtherSeqNewer(config)) { @@ -3563,7 +3701,7 @@ public final class ActivityThread { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: " + config); - applyConfigurationToResourcesLocked(config, compat); + diff = applyConfigurationToResourcesLocked(config, compat); if (mConfiguration == null) { mConfiguration = new Configuration(); @@ -3582,7 +3720,20 @@ public final class ActivityThread { if (callbacks != null) { final int N = callbacks.size(); for (int i=0; i<N; i++) { - performConfigurationChanged(callbacks.get(i), config); + ComponentCallbacks2 cb = callbacks.get(i); + + // We removed the old resources object from the mActiveResources + // cache, now we need to trigger an update for each application. + if ((diff & ActivityInfo.CONFIG_THEME_RESOURCE) != 0) { + if (cb instanceof Activity || cb instanceof Application) { + Context context = ((ContextWrapper)cb).getBaseContext(); + if (context instanceof ContextImpl) { + ((ContextImpl)context).refreshResourcesIfNecessary(); + } + } + } + + performConfigurationChanged(cb, config); } } } @@ -4356,7 +4507,7 @@ public final class ActivityThread { // We need to apply this change to the resources // immediately, because upon returning the view // hierarchy will be informed about it. - if (applyConfigurationToResourcesLocked(newConfig, null)) { + if (applyConfigurationToResourcesLocked(newConfig, null) != 0) { // This actually changed the resources! Tell // everyone about it. if (mPendingConfiguration == null || diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 180a442..ce8fd39 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -403,6 +403,16 @@ final class ApplicationPackageManager extends PackageManager { @SuppressWarnings("unchecked") @Override + public List<PackageInfo> getInstalledThemePackages() { + try { + return mPM.getInstalledThemePackages(); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + + @SuppressWarnings("unchecked") + @Override public List<ApplicationInfo> getInstalledApplications(int flags) { try { final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9d972b9..a8e40fd 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,15 +19,17 @@ package android.app; import com.android.internal.policy.PolicyManager; +import android.accounts.AccountManager; +import android.accounts.IAccountManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.IContentProvider; +import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; -import android.content.IIntentReceiver; import android.content.IntentSender; import android.content.ReceiverCallNotAllowedException; import android.content.ServiceConnection; @@ -36,6 +39,8 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.content.res.CustomTheme; import android.content.res.Resources; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; @@ -491,6 +496,20 @@ class ContextImpl extends Context { return mResources; } + /** + * Refresh resources object which may have been changed by a theme + * configuration change. + */ + /* package */ void refreshResourcesIfNecessary() { + if (mResources == Resources.getSystem()) { + return; + } + + if (mPackageInfo.mCompatibilityInfo.get().isThemeable) { + mTheme = null; + } + } + @Override public PackageManager getPackageManager() { if (mPackageManager != null) { |