diff options
Diffstat (limited to 'services/java')
13 files changed, 846 insertions, 36 deletions
diff --git a/services/java/com/android/server/AppsLaunchFailureReceiver.java b/services/java/com/android/server/AppsLaunchFailureReceiver.java new file mode 100644 index 0000000..6ef07aa --- /dev/null +++ b/services/java/com/android/server/AppsLaunchFailureReceiver.java @@ -0,0 +1,73 @@ +/* + * 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. + * 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.server; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.content.res.CustomTheme; +import android.util.Log; +import android.app.ActivityManager; +import android.os.SystemClock; + +public class AppsLaunchFailureReceiver extends BroadcastReceiver { + + private static final int FAILURES_THRESHOLD = 5; + private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds + + private int mFailuresCount = 0; + private long mStartTime = 0; + + // This function implements the following logic. + // If after a theme was applied the number of application launch failures + // at any moment was equal to FAILURES_THRESHOLD + // in less than EXPIRATION_TIME_IN_MILLISECONDS + // the default theme is applied unconditionally. + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE)) { + long currentTime = SystemClock.uptimeMillis(); + if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) { + // reset both the count and the timer + mStartTime = currentTime; + mFailuresCount = 0; + } + if (mFailuresCount <= FAILURES_THRESHOLD) { + mFailuresCount++; + if (mFailuresCount == FAILURES_THRESHOLD) { + CustomTheme defaultTheme = CustomTheme.getSystemTheme(); + ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); + Configuration currentConfig = am.getConfiguration(); + currentConfig.customTheme = new CustomTheme( + defaultTheme.getThemeId(), + defaultTheme.getThemePackageName()); + am.updateConfiguration(currentConfig); + } + } + } else if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE_RESET)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) || + action.equals(Intent.ACTION_PACKAGE_REMOVED)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } + } + +} diff --git a/services/java/com/android/server/AssetRedirectionManagerService.java b/services/java/com/android/server/AssetRedirectionManagerService.java new file mode 100644 index 0000000..1e124b9 --- /dev/null +++ b/services/java/com/android/server/AssetRedirectionManagerService.java @@ -0,0 +1,397 @@ +package com.android.server; + +import com.android.internal.app.IAssetRedirectionManager; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ThemeInfo; +import android.content.res.AssetManager; +import android.content.res.PackageRedirectionMap; +import android.content.res.Resources; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +public class AssetRedirectionManagerService extends IAssetRedirectionManager.Stub { + private static final String TAG = "AssetRedirectionManager"; + + private final Context mContext; + + /* + * TODO: This data structure should have some way to expire very old cache + * entries. Would be nice to optimize for the removal path as well. + */ + private final HashMap<RedirectionKey, PackageRedirectionMap> mRedirections = + new HashMap<RedirectionKey, PackageRedirectionMap>(); + + public AssetRedirectionManagerService(Context context) { + mContext = context; + } + + @Override + public void clearRedirectionMapsByTheme(String themePackageName, String themeId) + throws RemoteException { + synchronized (mRedirections) { + Set<RedirectionKey> keys = mRedirections.keySet(); + Iterator<RedirectionKey> iter = keys.iterator(); + while (iter.hasNext()) { + RedirectionKey key = iter.next(); + if (themePackageName.equals(key.themePackageName) && + (themeId == null || themeId.equals(key.themeId))) { + iter.remove(); + } + } + } + } + + @Override + public void clearPackageRedirectionMap(String targetPackageName) throws RemoteException { + synchronized (mRedirections) { + Set<RedirectionKey> keys = mRedirections.keySet(); + Iterator<RedirectionKey> iter = keys.iterator(); + while (iter.hasNext()) { + RedirectionKey key = iter.next(); + if (targetPackageName.equals(key.targetPackageName)) { + iter.remove(); + } + } + } + } + + @Override + public PackageRedirectionMap getPackageRedirectionMap(String themePackageName, + String themeId, String targetPackageName) throws RemoteException { + synchronized (mRedirections) { + RedirectionKey key = new RedirectionKey(); + key.themePackageName = themePackageName; + key.themeId = themeId; + key.targetPackageName = targetPackageName; + + PackageRedirectionMap map = mRedirections.get(key); + if (map != null) { + return map; + } else { + map = generatePackageRedirectionMap(key); + if (map != null) { + mRedirections.put(key, map); + } + return map; + } + } + } + + private PackageRedirectionMap generatePackageRedirectionMap(RedirectionKey key) { + AssetManager assets = new AssetManager(); + + boolean frameworkAssets = key.targetPackageName.equals("android"); + + if (!frameworkAssets) { + PackageInfo pi = getPackageInfo(mContext, key.targetPackageName); + if (pi == null || pi.applicationInfo == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to attach target package assets for " + key.targetPackageName); + return null; + } + } + + PackageInfo pi = getPackageInfo(mContext, key.themePackageName); + if (pi == null || pi.applicationInfo == null || pi.themeInfos == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to attach theme package assets from " + key.themePackageName); + return null; + } + + PackageRedirectionMap resMap = new PackageRedirectionMap(); + + /* + * Apply a special redirection hack for the highest level <style> + * replacing @android:style/Theme. + */ + if (frameworkAssets) { + int themeResourceId = findThemeResourceId(pi.themeInfos, key.themeId); + assets.generateStyleRedirections(resMap.getNativePointer(), android.R.style.Theme, + themeResourceId); + } + + Resources res = new Resources(assets, null, null); + generateExplicitRedirections(resMap, res, key.themePackageName, key.targetPackageName); + + return resMap; + } + + private void generateExplicitRedirections(PackageRedirectionMap resMap, Resources res, + String themePackageName, String targetPackageName) { + /* + * XXX: We should be parsing the <theme> tag's <meta-data>! Instead, + * we're just assuming that res/xml/<package>.xml exists and describes + * the redirects we want! + */ + String redirectXmlName = targetPackageName.replace('.', '_'); + int redirectXmlResId = res.getIdentifier(redirectXmlName, "xml", themePackageName); + if (redirectXmlResId == 0) { + return; + } + + ResourceRedirectionsProcessor processor = new ResourceRedirectionsProcessor(res, + redirectXmlResId, themePackageName, targetPackageName, resMap); + processor.process(); + } + + private static PackageInfo getPackageInfo(Context context, String packageName) { + try { + return context.getPackageManager().getPackageInfo(packageName, 0); + } catch (NameNotFoundException e) { + return null; + } + } + + /** + * Searches for the high-level theme resource id for the specific + * <theme> tag being applied. + * <p> + * An individual theme package can contain multiple <theme> tags, each + * representing a separate theme choice from the user's perspective, even + * though the most common case is for there to be only 1. + * + * @return The style resource id or 0 if no match was found. + */ + private static int findThemeResourceId(ThemeInfo[] themeInfos, String needle) { + if (themeInfos != null && !TextUtils.isEmpty(needle)) { + int n = themeInfos.length; + for (int i = 0; i < n; i++) { + ThemeInfo info = themeInfos[i]; + if (needle.equals(info.themeId)) { + return info.styleResourceId; + } + } + } + return 0; + } + + private static Resources getUnredirectedResourcesForPackage(Context context, String packageName) { + AssetManager assets = new AssetManager(); + + if (!packageName.equals("android")) { + PackageInfo pi = getPackageInfo(context, packageName); + if (pi == null || pi.applicationInfo == null || + assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) { + Log.w(TAG, "Unable to get resources for package " + packageName); + return null; + } + } + + return new Resources(assets, null, null); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mRedirections) { + final ArrayList<RedirectionKey> filteredKeySet = new ArrayList<RedirectionKey>(); + for (Map.Entry<RedirectionKey, PackageRedirectionMap> entry: mRedirections.entrySet()) { + PackageRedirectionMap map = entry.getValue(); + if (map != null && map.getPackageId() != -1) { + filteredKeySet.add(entry.getKey()); + } + } + Collections.sort(filteredKeySet, new Comparator<RedirectionKey>() { + @Override + public int compare(RedirectionKey a, RedirectionKey b) { + int comp = a.themePackageName.compareTo(b.themePackageName); + if (comp != 0) { + return comp; + } + comp = a.themeId.compareTo(b.themeId); + if (comp != 0) { + return comp; + } + return a.targetPackageName.compareTo(b.targetPackageName); + } + }); + + pw.println("Theme asset redirections:"); + String lastPackageName = null; + String lastId = null; + Resources themeRes = null; + for (RedirectionKey key: filteredKeySet) { + if (lastPackageName == null || !lastPackageName.equals(key.themePackageName)) { + pw.println("* Theme package " + key.themePackageName + ":"); + lastPackageName = key.themePackageName; + themeRes = getUnredirectedResourcesForPackage(mContext, key.themePackageName); + } + if (lastId == null || !lastId.equals(key.themeId)) { + pw.println(" theme id #" + key.themeId + ":"); + lastId = key.themeId; + } + pw.println(" " + key.targetPackageName + ":"); + Resources targetRes = getUnredirectedResourcesForPackage(mContext, key.targetPackageName); + PackageRedirectionMap resMap = mRedirections.get(key); + int[] fromIdents = resMap.getRedirectionKeys(); + int N = fromIdents.length; + for (int i = 0; i < N; i++) { + int fromIdent = fromIdents[i]; + int toIdent = resMap.lookupRedirection(fromIdent); + String fromName = targetRes != null ? targetRes.getResourceName(fromIdent) : null; + String toName = themeRes != null ? themeRes.getResourceName(toIdent) : null; + pw.println(String.format(" %s (0x%08x) => %s (0x%08x)", fromName, fromIdent, + toName, toIdent)); + } + } + } + } + + private static class RedirectionKey { + public String themePackageName; + public String themeId; + public String targetPackageName; + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof RedirectionKey)) return false; + final RedirectionKey oo = (RedirectionKey)o; + if (!nullSafeEquals(themePackageName, oo.themePackageName)) { + return false; + } + if (!nullSafeEquals(themeId, oo.themeId)) { + return false; + } + if (!nullSafeEquals(targetPackageName, oo.targetPackageName)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return themePackageName.hashCode() + + themeId.hashCode() + + targetPackageName.hashCode(); + } + + private static boolean nullSafeEquals(Object a, Object b) { + if (a == null) { + return b == a; + } else if (b == null) { + return false; + } else { + return a.equals(b); + } + } + } + + /** + * Parses and processes explicit redirection XML files. + */ + private static class ResourceRedirectionsProcessor { + private final Resources mResources; + private final XmlPullParser mParser; + private final int mResourceId; + private final String mThemePackageName; + private final String mTargetPackageName; + private final PackageRedirectionMap mResMap; + + public ResourceRedirectionsProcessor(Resources res, int resourceId, + String themePackageName, String targetPackageName, + PackageRedirectionMap outMap) { + mResources = res; + mParser = res.getXml(resourceId); + mResourceId = resourceId; + mThemePackageName = themePackageName; + mTargetPackageName = targetPackageName; + mResMap = outMap; + } + + public void process() { + XmlPullParser parser = mParser; + int type; + try { + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // just loop... + } + + String tagName = parser.getName(); + if (parser.getName().equals("resource-redirections")) { + processResourceRedirectionsTag(); + } else { + Log.w(TAG, "Unknown root element: " + tagName + " at " + getResourceLabel() + " " + + parser.getPositionDescription()); + } + } catch (XmlPullParserException e) { + Log.w(TAG, "Malformed theme redirection meta at " + getResourceLabel()); + } catch (IOException e) { + Log.w(TAG, "Unknown error reading redirection meta at " + getResourceLabel()); + } + } + + private void processResourceRedirectionsTag() throws XmlPullParserException, IOException { + XmlPullParser parser = mParser; + int type; + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && + (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("item")) { + processItemTag(); + } else { + Log.w(TAG, "Unknown element under <resource-redirections>: " + tagName + + " at " + getResourceLabel() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + } + + private void processItemTag() throws XmlPullParserException, IOException { + XmlPullParser parser = mParser; + String fromName = parser.getAttributeValue(null, "name"); + if (TextUtils.isEmpty(fromName)) { + Log.w(TAG, "Missing android:name attribute on <item> tag at " + getResourceLabel() + " " + + parser.getPositionDescription()); + return; + } + String toName = parser.nextText(); + if (TextUtils.isEmpty(toName)) { + Log.w(TAG, "Missing <item> text at " + getResourceLabel() + " " + + parser.getPositionDescription()); + return; + } + int fromIdent = mResources.getIdentifier(fromName, null, mTargetPackageName); + if (fromIdent == 0) { + Log.w(TAG, "No such resource found for " + mTargetPackageName + ":" + fromName); + return; + } + int toIdent = mResources.getIdentifier(toName, null, mThemePackageName); + if (toIdent == 0) { + Log.w(TAG, "No such resource found for " + mThemePackageName + ":" + toName); + return; + } + mResMap.addRedirection(fromIdent, toIdent); + } + + private String getResourceLabel() { + return "resource #0x" + Integer.toHexString(mResourceId); + } + } +} diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index 94a087a..cce5653 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -19,9 +19,11 @@ package com.android.server; import java.io.FileDescriptor; import java.io.PrintWriter; +import com.android.internal.app.ThemeUtils; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -84,6 +86,7 @@ public class DeviceStorageMonitorService extends Binder { private boolean mLowMemFlag=false; private boolean mMemFullFlag=false; private Context mContext; + private Context mUiContext; private ContentResolver mContentResolver; private long mTotalMemory; // on /data private StatFs mDataFileStats; @@ -345,6 +348,14 @@ public class DeviceStorageMonitorService extends Binder { mLastReportedFreeMemTime = 0; mContext = context; mContentResolver = mContext.getContentResolver(); + + ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() { + @Override + public void onReceive(Context content, Intent intent) { + mUiContext = null; + } + }); + //create StatFs object mDataFileStats = new StatFs(DATA_PATH); mSystemFileStats = new StatFs(SYSTEM_PATH); @@ -402,7 +413,7 @@ public class DeviceStorageMonitorService extends Binder { notification.icon = com.android.internal.R.drawable.stat_notify_disk_full; notification.tickerText = title; notification.flags |= Notification.FLAG_NO_CLEAR; - notification.setLatestEventInfo(mContext, title, details, intent); + notification.setLatestEventInfo(getUiContext(), title, details, intent); mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification, UserHandle.ALL); mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); @@ -515,4 +526,11 @@ public class DeviceStorageMonitorService extends Binder { pw.print(" mMemCacheTrimToThreshold="); pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold)); } + + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index b11432d..445a4bb 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -15,6 +15,7 @@ package com.android.server; +import com.android.internal.app.ThemeUtils; import com.android.internal.content.PackageMonitor; import com.android.internal.os.HandlerCaller; import com.android.internal.os.SomeArgs; @@ -165,6 +166,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final Locale ENGLISH_LOCALE = new Locale("en"); final Context mContext; + private Context mUiContext; final Resources mRes; final Handler mHandler; final InputMethodSettings mSettings; @@ -848,6 +850,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }); + mStatusBar = statusBar; statusBar.setIconVisibility("ime", false); updateImeWindowStatusLocked(); @@ -2525,6 +2534,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } + // ---------------------------------------------------------------------- private void showInputMethodMenu() { @@ -2561,7 +2577,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private void showInputMethodMenuInternal(boolean showSubtypes) { if (DEBUG) Slog.v(TAG, "Show switching menu"); - final Context context = mContext; + final Context context = getUiContext(); final boolean isScreenLocked = isScreenLocked(); final String lastInputMethodId = mSettings.getSelectedInputMethod(); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index af49135..5f0187c 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -79,6 +79,9 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.File; + +import com.android.internal.app.ThemeUtils; + import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -122,6 +125,7 @@ public class NotificationManagerService extends INotificationManager.Stub private static final boolean ENABLE_BLOCKED_TOASTS = true; final Context mContext; + Context mUiContext; final IActivityManager mAm; final IBinder mForegroundToken = new Binder(); @@ -533,6 +537,13 @@ public class NotificationManagerService extends INotificationManager.Stub } }; + private BroadcastReceiver mThemeChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }; + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -766,6 +777,7 @@ public class NotificationManagerService extends INotificationManager.Stub ledObserver.observe(); QuietHoursSettingsObserver qhObserver = new QuietHoursSettingsObserver(mHandler); qhObserver.observe(); + ThemeUtils.registerThemeChangeReceiver(mContext, mThemeChangeReceiver); } void systemReady() { @@ -1634,6 +1646,13 @@ public class NotificationManagerService extends INotificationManager.Stub return -1; } + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } + private void updateNotificationPulse() { synchronized (mNotificationList) { updateLightsLocked(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3dd22b0..cec8a4c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.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. @@ -24,6 +25,7 @@ import android.content.ContentResolver; import android.content.ContentService; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.res.Configuration; import android.media.AudioService; @@ -757,6 +759,13 @@ class ServerThread extends Thread { reportWtf("starting DreamManagerService", e); } } + + try { + Slog.i(TAG, "AssetRedirectionManager Service"); + ServiceManager.addService("assetredirection", new AssetRedirectionManagerService(context)); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting AssetRedirectionManager Service", e); + } } // Before things start rolling, be sure we have decided whether @@ -840,6 +849,15 @@ class ServerThread extends Thread { reportWtf("making Display Manager Service ready", e); } + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE); + filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE_RESET); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE); + filter.addDataScheme("package"); + context.registerReceiver(new AppsLaunchFailureReceiver(), filter); + // These are needed to propagate to the runnable below. final Context contextF = context; final MountService mountServiceF = mountService; diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java index 75eb3c4..9bc3a91 100644 --- a/services/java/com/android/server/ThrottleService.java +++ b/services/java/com/android/server/ThrottleService.java @@ -53,6 +53,7 @@ import android.util.Slog; import android.util.TrustedTime; import com.android.internal.R; +import com.android.internal.app.ThemeUtils; import com.android.internal.telephony.TelephonyProperties; import java.io.BufferedWriter; @@ -80,6 +81,7 @@ public class ThrottleService extends IThrottleManager.Stub { private HandlerThread mThread; private Context mContext; + private Context mUiContext; private static final int INITIAL_POLL_DELAY_SEC = 90; private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1; @@ -339,6 +341,13 @@ public class ThrottleService extends IThrottleManager.Stub { } }, new IntentFilter(ACTION_RESET)); + ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }); + // use a new thread as we don't want to stall the system for file writes mThread = new HandlerThread(TAG); mThread.start(); @@ -685,12 +694,18 @@ public class ThrottleService extends IThrottleManager.Stub { } mThrottlingNotification.flags = flags; mThrottlingNotification.tickerText = title; - mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi); + mThrottlingNotification.setLatestEventInfo(getUiContext(), title, message, pi); mNotificationManager.notifyAsUser(null, mThrottlingNotification.icon, mThrottlingNotification, UserHandle.ALL); } + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } private void clearThrottleAndNotification() { if (mThrottleIndex.get() != THROTTLE_INDEX_UNTHROTTLED) { diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 0e456f1..797990e 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -48,6 +48,7 @@ import java.io.PrintWriter; import com.android.internal.R; import com.android.internal.app.DisableCarModeActivity; import com.android.server.TwilightService.TwilightState; +import com.android.internal.app.ThemeUtils; final class UiModeManagerService extends IUiModeManager.Stub { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -60,6 +61,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { private final Context mContext; private final TwilightService mTwilightService; private final Handler mHandler = new Handler(); + private Context mUiContext; final Object mLock = new Object(); @@ -142,6 +144,13 @@ final class UiModeManagerService extends IUiModeManager.Stub { } }; + private final BroadcastReceiver mThemeChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }; + private final TwilightService.TwilightListener mTwilightListener = new TwilightService.TwilightListener() { @Override @@ -161,6 +170,8 @@ final class UiModeManagerService extends IUiModeManager.Stub { mContext.registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + ThemeUtils.registerThemeChangeReceiver(mContext, mThemeChangeReceiver); + mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); @@ -549,7 +560,7 @@ final class UiModeManagerService extends IUiModeManager.Stub { n.flags = Notification.FLAG_ONGOING_EVENT; n.when = 0; n.setLatestEventInfo( - mContext, + getUiContext(), mContext.getString(R.string.car_mode_disable_notification_title), mContext.getString(R.string.car_mode_disable_notification_message), PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0, @@ -579,6 +590,13 @@ final class UiModeManagerService extends IUiModeManager.Stub { } } + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d2cd646..a747f0b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006-2008 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. @@ -19,6 +20,7 @@ package com.android.server.am; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import com.android.internal.R; +import com.android.internal.app.ThemeUtils; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessStats; import com.android.internal.widget.LockPatternUtils; @@ -87,6 +89,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.CustomTheme; import android.graphics.Bitmap; import android.net.Proxy; import android.net.ProxyProperties; @@ -160,6 +163,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import dalvik.system.Zygote; public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { @@ -667,6 +671,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mLaunchWarningShown = false; Context mContext; + Context mUiContext; int mFactoryTest; @@ -936,7 +941,7 @@ public final class ActivityManagerService extends ActivityManagerNative return; } if (mShowDialogs && !mSleeping && !mShuttingDown) { - Dialog d = new AppErrorDialog(mContext, + Dialog d = new AppErrorDialog(getUiContext(), ActivityManagerService.this, res, proc); d.show(); proc.crashDialog = d; @@ -971,7 +976,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mShowDialogs) { Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (ActivityRecord)data.get("activity"), + getUiContext(), proc, (ActivityRecord)data.get("activity"), msg.arg1 != 0); d.show(); proc.anrDialog = d; @@ -997,7 +1002,7 @@ public final class ActivityManagerService extends ActivityManagerNative } AppErrorResult res = (AppErrorResult) data.get("result"); if (mShowDialogs && !mSleeping && !mShuttingDown) { - Dialog d = new StrictModeViolationDialog(mContext, + Dialog d = new StrictModeViolationDialog(getUiContext(), ActivityManagerService.this, res, proc); d.show(); proc.crashDialog = d; @@ -1011,7 +1016,7 @@ public final class ActivityManagerService extends ActivityManagerNative } break; case SHOW_FACTORY_ERROR_MSG: { Dialog d = new FactoryErrorDialog( - mContext, msg.getData().getCharSequence("msg")); + getUiContext(), msg.getData().getCharSequence("msg")); d.show(); ensureBootCompleted(); } break; @@ -1031,7 +1036,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (!app.waitedForDebugger) { Dialog d = new AppWaitingForDebuggerDialog( ActivityManagerService.this, - mContext, app); + getUiContext(), app); app.waitDialog = d; app.waitedForDebugger = true; d.show(); @@ -1113,7 +1118,7 @@ public final class ActivityManagerService extends ActivityManagerNative Log.e(TAG, title + ": " + text); if (mShowDialogs) { // XXX This is a temporary dialog, no need to localize. - AlertDialog d = new BaseErrorDialog(mContext); + AlertDialog d = new BaseErrorDialog(getUiContext()); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); d.setCancelable(false); d.setTitle(title); @@ -1184,7 +1189,7 @@ public final class ActivityManagerService extends ActivityManagerNative notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; - notification.setLatestEventInfo(context, text, + notification.setLatestEventInfo(getUiContext(), text, mContext.getText(R.string.heavy_weight_notification_detail), PendingIntent.getActivityAsUser(mContext, 0, root.intent, PendingIntent.FLAG_CANCEL_CURRENT, null, @@ -1799,6 +1804,15 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private Context getUiContext() { + synchronized (this) { + if (mUiContext == null && mBooted) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } + } + /** * Initialize the application bind args. These are passed to each * process when the bindApplication() IPC is sent to the process. They're @@ -3407,7 +3421,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void run() { synchronized (ActivityManagerService.this) { - final Dialog d = new LaunchWarningWindow(mContext, cur, next); + final Dialog d = new LaunchWarningWindow(getUiContext(), cur, next); d.show(); mHandler.postDelayed(new Runnable() { @Override @@ -4390,6 +4404,13 @@ public final class ActivityManagerService extends ActivityManagerNative } }, pkgFilter); + ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }); + synchronized (this) { // Ensure that any processes we had put on hold are now started // up. @@ -12310,6 +12331,11 @@ public final class ActivityManagerService extends ActivityManagerNative values.userSetLocale); } + if (values.customTheme != null) { + saveThemeResourceLocked(values.customTheme, + !values.customTheme.equals(mConfiguration.customTheme)); + } + mConfigurationSeq++; if (mConfigurationSeq <= 0) { mConfigurationSeq = 1; @@ -12529,6 +12555,13 @@ public final class ActivityManagerService extends ActivityManagerNative return srec.launchedFromUid; } + private void saveThemeResourceLocked(CustomTheme t, boolean isDiff){ + if(isDiff){ + SystemProperties.set(Configuration.THEME_ID_PERSISTENCE_PROPERTY, t.getThemeId()); + SystemProperties.set(Configuration.THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY, t.getThemePackageName()); + } + } + // ========================================================= // LIFETIME MANAGEMENT // ========================================================= diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index e4a7ead..8f154b1 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -47,6 +47,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; +import com.android.internal.app.ThemeUtils; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IState; @@ -74,6 +75,7 @@ import java.util.Set; public class Tethering extends INetworkManagementEventObserver.Stub { private Context mContext; + private Context mUiContext; private final static String TAG = "Tethering"; private final static boolean DBG = true; private final static boolean VDBG = false; @@ -158,6 +160,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(mStateReceiver, filter); + ThemeUtils.registerThemeChangeReceiver(mContext, new BroadcastReceiver() { + @Override + public void onReceive(Context content, Intent intent) { + mUiContext = null; + } + }); + filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_SHARED); filter.addAction(Intent.ACTION_MEDIA_UNSHARED); @@ -478,12 +487,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND; mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT; mTetheredNotification.tickerText = title; - mTetheredNotification.setLatestEventInfo(mContext, title, message, pi); + mTetheredNotification.setLatestEventInfo(getUiContext(), title, message, pi); notificationManager.notifyAsUser(null, mTetheredNotification.icon, mTetheredNotification, UserHandle.ALL); } + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; + } + private void clearTetheredNotification() { NotificationManager notificationManager = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 83672c5..0cbfa6f 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.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. @@ -31,6 +32,7 @@ import static libcore.io.OsConstants.S_IXGRP; import static libcore.io.OsConstants.S_IROTH; import static libcore.io.OsConstants.S_IXOTH; +import com.android.internal.app.IAssetRedirectionManager; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.internal.content.NativeLibraryHelper; @@ -143,6 +145,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -150,6 +153,9 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; import libcore.io.ErrnoException; import libcore.io.IoUtils; @@ -201,6 +207,8 @@ public class PackageManagerService extends IPackageManager.Stub { // package apks to install directory. private static final String INSTALL_PACKAGE_SUFFIX = "-"; + private static final int THEME_MAMANER_GUID = 1300; + static final int SCAN_MONITOR = 1<<0; static final int SCAN_NO_DEX = 1<<1; static final int SCAN_FORCE_DEX = 1<<2; @@ -407,6 +415,8 @@ public class PackageManagerService extends IPackageManager.Stub { ComponentName mResolveComponentName; PackageParser.Package mPlatformPackage; + IAssetRedirectionManager mAssetRedirectionManager; + // Set of pending broadcasts for aggregating enable/disable of components. final HashMap<String, ArrayList<String>> mPendingBroadcasts = new HashMap<String, ArrayList<String>>(); @@ -706,7 +716,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageInstalledInfo res = data.res; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - res.removedInfo.sendBroadcast(false, true, false); + res.removedInfo.sendBroadcast(false, true, false, false); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); // Determine the set of users who are adding this @@ -743,21 +753,25 @@ public class PackageManagerService extends IPackageManager.Stub { } } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, - res.pkg.applicationInfo.packageName, + res.pkg.applicationInfo.packageName, null, extras, null, null, firstUsers); final boolean update = res.removedInfo.removedPackage != null; if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } + String category = null; + if(res.pkg.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, - res.pkg.applicationInfo.packageName, + res.pkg.applicationInfo.packageName, category, extras, null, null, updateUsers); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, - res.pkg.applicationInfo.packageName, + res.pkg.applicationInfo.packageName, category, extras, null, null, updateUsers); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, - null, null, + null, null, null, res.pkg.applicationInfo.packageName, null, updateUsers); } if (res.removedInfo.args != null) { @@ -975,6 +989,7 @@ public class PackageManagerService extends IPackageManager.Stub { Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM); + mSettings.addSharedUserLPw("com.tmobile.thememanager", THEME_MAMANER_GUID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM); @@ -2938,6 +2953,20 @@ public class PackageManagerService extends IPackageManager.Stub { return list; } + public List<PackageInfo> getInstalledThemePackages() { + // Returns a list of theme APKs. + ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); + List<PackageInfo> installedPackagesList = mContext.getPackageManager().getInstalledPackages(0); + Iterator<PackageInfo> i = installedPackagesList.iterator(); + while (i.hasNext()) { + final PackageInfo pi = i.next(); + if (pi != null && pi.isThemeApk) { + finalList.add(pi); + } + } + return finalList; + } + @Override public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, String lastRead, int userId) { @@ -4495,6 +4524,32 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // NOTE: this method can return null if the SystemServer is still + // initializing + public IAssetRedirectionManager getAssetRedirectionManager() { + if (mAssetRedirectionManager != null) { + return mAssetRedirectionManager; + } + IBinder b = ServiceManager.getService("assetredirection"); + mAssetRedirectionManager = IAssetRedirectionManager.Stub.asInterface(b); + return mAssetRedirectionManager; + } + + private void cleanAssetRedirections(PackageParser.Package pkg) { + IAssetRedirectionManager rm = getAssetRedirectionManager(); + if (rm == null) { + return; + } + try { + if (pkg.mIsThemeApk) { + rm.clearRedirectionMapsByTheme(pkg.packageName, null); + } else { + rm.clearPackageRedirectionMap(pkg.packageName); + } + } catch (RemoteException e) { + } + } + void removePackageLI(PackageSetting ps, boolean chatty) { if (DEBUG_INSTALL) { if (chatty) @@ -4523,6 +4578,8 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { + cleanAssetRedirections(pkg); + mPackages.remove(pkg.applicationInfo.packageName); if (pkg.mPath != null) { mAppDirs.remove(pkg.mPath); @@ -5367,7 +5424,7 @@ public class PackageManagerService extends IPackageManager.Stub { } }; - static final void sendPackageBroadcast(String action, String pkg, + static final void sendPackageBroadcast(String action, String pkg, String intentCategory, Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds) { IActivityManager am = ActivityManagerNative.getDefault(); @@ -5400,6 +5457,9 @@ public class PackageManagerService extends IPackageManager.Stub { + intent.toShortString(false, true, false, false) + " " + intent.getExtras(), here); } + if (intentCategory != null) { + intent.addCategory(intentCategory); + } am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, finishedReceiver != null, false, id); } @@ -5483,6 +5543,7 @@ public class PackageManagerService extends IPackageManager.Stub { String addedPackage = null; int addedAppId = -1; int[] addedUsers = null; + String category = null; // TODO post a message to the handler to obtain serial ordering synchronized (mInstallLock) { @@ -5513,6 +5574,9 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { p = mAppDirs.get(fullPathStr); if (p != null) { + if (p.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } ps = mSettings.mPackages.get(p.applicationInfo.packageName); if (ps != null) { removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); @@ -5554,6 +5618,9 @@ public class PackageManagerService extends IPackageManager.Stub { addedAppId = UserHandle.getAppId(p.applicationInfo.uid); } } + if (p != null && p.mIsThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } } // reader @@ -5566,13 +5633,13 @@ public class PackageManagerService extends IPackageManager.Stub { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedAppId); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras, null, null, removedUsers); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedAppId); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, category, extras, null, null, addedUsers); } } @@ -5669,7 +5736,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (sendAdded) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, null, packageName, extras, null, null, new int[] {userId}); } } finally { @@ -7791,6 +7858,24 @@ public class PackageManagerService extends IPackageManager.Stub { Log.d(TAG, "New package installed in " + newPackage.mPath); + cleanAssetRedirections(newPackage); + + if (newPackage.mIsThemeApk) { + /* DBS-TODO + boolean isThemePackageDrmProtected = false; + int N = newPackage.mThemeInfos.size(); + for (int i = 0; i < N; i++) { + if (newPackage.mThemeInfos.get(i).isDrmProtected) { + isThemePackageDrmProtected = true; + break; + } + } + if (isThemePackageDrmProtected) { + splitThemePackage(newPackage.mPath); + } + */ + } + synchronized (mPackages) { updatePermissionsLPw(newPackage.packageName, newPackage, UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0 @@ -7806,6 +7891,65 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private void deleteLockedZipFileIfExists(String originalPackagePath) { + String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath); + File zipFile = new File(lockedZipFilePath); + if (zipFile.exists() && zipFile.isFile()) { + if (!zipFile.delete()) { + Log.w(TAG, "Couldn't delete locked zip file: " + originalPackagePath); + } + } + } + private void splitThemePackage(File originalFile) { + final String originalPackagePath = originalFile.getPath(); + final String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath); + + try { + final List<String> drmProtectedEntries = new ArrayList<String>(); + final ZipFile privateZip = new ZipFile(originalFile.getPath()); + + final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries(); + while (privateZipEntries.hasMoreElements()) { + final ZipEntry zipEntry = privateZipEntries.nextElement(); + final String zipEntryName = zipEntry.getName(); + if (zipEntryName.startsWith("assets/") && zipEntryName.contains("/locked/")) { + drmProtectedEntries.add(zipEntryName); + } + } + privateZip.close(); + + String [] args = new String[0]; + args = drmProtectedEntries.toArray(args); + int code = mContext.getAssets().splitDrmProtectedThemePackage( + originalPackagePath, + lockedZipFilePath, + args); + if (code != 0) { + Log.e("PackageManagerService", + "splitDrmProtectedThemePackage returned = " + code); + } + code = FileUtils.setPermissions( + lockedZipFilePath, + 0640, + -1, + THEME_MAMANER_GUID); + if (code != 0) { + Log.e("PackageManagerService", + "Set permissions for " + lockedZipFilePath + " returned = " + code); + } + code = FileUtils.setPermissions( + originalPackagePath, + 0644, + -1, -1); + if (code != 0) { + Log.e("PackageManagerService", + "Set permissions for " + originalPackagePath + " returned = " + code); + } + } catch (IOException e) { + Log.e(TAG, "Failure to generate new zip files for theme"); + } + } + private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) { int pFlags = args.flags; @@ -8066,6 +8210,18 @@ public class PackageManagerService extends IPackageManager.Stub { boolean removedForAllUsers = false; boolean systemUpdate = false; + + synchronized (mPackages) { + PackageParser.Package p = mPackages.get(packageName); + if (p != null) { + info.isThemeApk = p.mIsThemeApk; + if (info.isThemeApk && + !info.isRemovedPackageSystemUpdate) { + deleteLockedZipFileIfExists(p.mPath); + } + } + } + synchronized (mInstallLock) { res = deletePackageLI(packageName, (flags & PackageManager.DELETE_ALL_USERS) != 0 @@ -8078,7 +8234,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (res) { - info.sendBroadcast(true, systemUpdate, removedForAllUsers); + info.sendBroadcast(true, systemUpdate, removedForAllUsers, true); // If the removed package was a system update, the old system package // was re-enabled; we need to broadcast this information @@ -8088,11 +8244,16 @@ public class PackageManagerService extends IPackageManager.Stub { ? info.removedAppId : info.uid); extras.putBoolean(Intent.EXTRA_REPLACING, true); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, + String category = null; + if (info.isThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } + + sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category, extras, null, null, null); - sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, + sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, category, extras, null, null, null); - sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, + sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, null, packageName, null, null); } } @@ -8117,8 +8278,10 @@ public class PackageManagerService extends IPackageManager.Stub { boolean isRemovedPackageSystemUpdate = false; // Clean up resources deleted packages. InstallArgs args = null; + boolean isThemeApk = false; - void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) { + void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers, + boolean deleteLockedZipFileIfExists) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove); @@ -8127,15 +8290,19 @@ public class PackageManagerService extends IPackageManager.Stub { } extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, + String category = null; + if (isThemeApk) { + category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE; + } + sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category, extras, null, null, removedUsers); if (fullRemove && !replacing) { - sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, + sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, category, extras, null, null, removedUsers); } } if (removedAppId >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null, + sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, null, extras, null, null, removedUsers); } } @@ -8714,6 +8881,7 @@ public class PackageManagerService extends IPackageManager.Stub { "replacePreferredActivity expects filter to have no data authorities, " + "paths, schemes or types."); } + synchronized (mPackages) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) @@ -8989,7 +9157,7 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null, + sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, null, extras, null, null, new int[] {UserHandle.getUserId(packageUid)}); } @@ -9654,7 +9822,7 @@ public class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver, null); + sendPackageBroadcast(action, null, null, extras, null, finishedReceiver, null); } } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 94494ae..15395d2 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -2478,7 +2478,7 @@ final class Settings { if (pkgSetting.getNotLaunched(userId)) { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, - pkgSetting.name, null, + pkgSetting.name, null, null, pkgSetting.installerPackageName, null, new int[] {userId}); } pkgSetting.setNotLaunched(false, userId); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 38233d0..0e5adbb 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -41,6 +41,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import com.android.internal.app.IBatteryStats; +import com.android.internal.app.ThemeUtils; + import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.PhoneWindowManager; import com.android.internal.view.IInputContext; @@ -295,6 +297,13 @@ public class WindowManagerService extends IWindowManager.Stub private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f; + + private BroadcastReceiver mThemeChangeReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + mUiContext = null; + } + }; + final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -310,6 +319,7 @@ public class WindowManagerService extends IWindowManager.Stub int mCurrentUserId; final Context mContext; + private Context mUiContext; final boolean mHaveInputMethods; @@ -847,6 +857,15 @@ public class WindowManagerService extends IWindowManager.Stub } finally { Surface.closeTransaction(); } + + ThemeUtils.registerThemeChangeReceiver(mContext, mThemeChangeReceiver); + } + + private Context getUiContext() { + if (mUiContext == null) { + mUiContext = ThemeUtils.createUiContext(mContext); + } + return mUiContext != null ? mUiContext : mContext; } public InputMonitor getInputMonitor() { @@ -5414,13 +5433,13 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override public void shutdown(boolean confirm) { - ShutdownThread.shutdown(mContext, confirm); + ShutdownThread.shutdown(getUiContext(), confirm); } // Called by window manager policy. Not exposed externally. @Override public void rebootSafeMode(boolean confirm) { - ShutdownThread.rebootSafeMode(mContext, confirm); + ShutdownThread.rebootSafeMode(getUiContext(), confirm); } public void setInputFilter(IInputFilter filter) { @@ -5433,7 +5452,7 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override public void reboot() { - ShutdownThread.reboot(mContext, null, true); + ShutdownThread.reboot(getUiContext(), null, true); } public void setCurrentUser(final int newUserId) { |
