diff options
author | d34d <clark@cyngn.com> | 2016-07-20 13:15:53 -0700 |
---|---|---|
committer | d34d <clark@cyngn.com> | 2016-07-20 13:15:53 -0700 |
commit | d63fd37c52fdf7b6e9c74b5883951cc121063299 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 | |
parent | 104f3230ed04e381205a29ba2c8674174d36bde6 (diff) | |
download | android_packages_services_ThemeManagerService-d63fd37c52fdf7b6e9c74b5883951cc121063299.tar.gz android_packages_services_ThemeManagerService-d63fd37c52fdf7b6e9c74b5883951cc121063299.tar.bz2 android_packages_services_ThemeManagerService-d63fd37c52fdf7b6e9c74b5883951cc121063299.zip |
Revert "Initial code checkin"
This reverts commit 104f3230ed04e381205a29ba2c8674174d36bde6.
-rw-r--r-- | Android.mk | 32 | ||||
-rw-r--r-- | AndroidManifest.xml | 40 | ||||
-rw-r--r-- | res/values/strings.xml | 19 | ||||
-rw-r--r-- | src/org/cyanogenmod/themeservice/AppsFailureReceiver.java | 119 | ||||
-rw-r--r-- | src/org/cyanogenmod/themeservice/ThemeManagerService.java | 1279 |
5 files changed, 0 insertions, 1489 deletions
diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 85b10b0..0000000 --- a/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2016 The CyanogenMod Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -# -# Theme manager service -# -include $(CLEAR_VARS) - -LOCAL_PACKAGE_NAME := ThemeManagerService - -LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.internal - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PRIVILEGED_MODULE := true - -include $(BUILD_PACKAGE) diff --git a/AndroidManifest.xml b/AndroidManifest.xml deleted file mode 100644 index 57b4f15..0000000 --- a/AndroidManifest.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="org.cyanogenmod.themeservice"> - - <uses-permission android:name="cyanogenmod.permission.ACCESS_THEME_MANAGER" /> - <uses-permission android:name="cyanogenmod.permission.READ_THEMES" /> - <uses-permission android:name="cyanogenmod.permission.WRITE_THEMES" /> - <uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" /> - <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" /> - <uses-permission android:name="cyanogenmod.permission.SEND_PROTECTED_THEME_BROADCAST" /> - - <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> - <uses-permission android:name="android.permission.SET_KEYGUARD_WALLPAPER" /> - <uses-permission android:name="android.permission.SET_WALLPAPER" /> - <uses-permission android:name="android.permission.WRITE_SETTINGS" /> - - <application android:label="@string/app_name"> - - <service android:name="org.cyanogenmod.themeservice.ThemeManagerService" - android:enabled="true" - android:exported="true"/> - - </application> -</manifest> diff --git a/res/values/strings.xml b/res/values/strings.xml deleted file mode 100644 index 7ff9e3b..0000000 --- a/res/values/strings.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2016 The CyanogenMod Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_name">Theme manager service</string> -</resources> diff --git a/src/org/cyanogenmod/themeservice/AppsFailureReceiver.java b/src/org/cyanogenmod/themeservice/AppsFailureReceiver.java deleted file mode 100644 index 98a6f42..0000000 --- a/src/org/cyanogenmod/themeservice/AppsFailureReceiver.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2010, T-Mobile USA, Inc. - * Copyright (C) 2015-2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.cyanogenmod.themeservice; - -import android.app.Notification; -import android.app.NotificationManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.res.ThemeConfig; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import cyanogenmod.app.CMContextConstants; -import cyanogenmod.themes.IThemeService; -import cyanogenmod.themes.ThemeChangeRequest; -import cyanogenmod.themes.ThemeChangeRequest.RequestType; -import org.cyanogenmod.internal.util.ThemeUtils; -import org.cyanogenmod.platform.internal.R; - -import static cyanogenmod.content.Intent.ACTION_APP_FAILURE; - -public class AppsFailureReceiver extends BroadcastReceiver { - - private static final int FAILURES_THRESHOLD = 3; - 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(); - final long currentTime = SystemClock.uptimeMillis(); - if (ACTION_APP_FAILURE.equals(action)) { - 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) { - // let the theme manager take care of getting us back on the default theme - IThemeService tm = IThemeService.Stub.asInterface(ServiceManager - .getService(CMContextConstants.CM_THEME_SERVICE)); - final String themePkgName = ThemeConfig.SYSTEM_DEFAULT; - ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); - builder.setOverlay(themePkgName) - .setStatusBar(themePkgName) - .setNavBar(themePkgName) - .setIcons(themePkgName) - .setFont(themePkgName) - .setBootanimation(themePkgName) - .setWallpaper(themePkgName) - .setLockWallpaper(themePkgName) - .setAlarm(themePkgName) - .setNotification(themePkgName) - .setRingtone(themePkgName) - .setRequestType(RequestType.THEME_RESET); - // Since we are resetting everything to the system theme, we can have the - // theme service remove all per app themes without setting them explicitly :) - try { - tm.requestThemeChange(builder.build(), true); - postThemeResetNotification(context); - } catch (RemoteException e) { - /* ignore */ - } - } - } - } else if (ThemeUtils.ACTION_THEME_CHANGED.equals(action)) { - // reset both the count and the timer - mStartTime = currentTime; - mFailuresCount = 0; - } - } - - /** - * Posts a notification to let the user know their theme was reset - * @param context - */ - private void postThemeResetNotification(Context context) { - NotificationManager nm = - (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - String title = context.getString(org.cyanogenmod.platform.internal.R.string.theme_reset_notification_title); - String body = context.getString(org.cyanogenmod.platform.internal.R.string.theme_reset_notification_message); - Notification notice = new Notification.Builder(context) - .setAutoCancel(true) - .setOngoing(false) - .setContentTitle(title) - .setContentText(body) - .setStyle(new Notification.BigTextStyle().bigText(body)) - .setSmallIcon(android.R.drawable.stat_notify_error) - .setWhen(System.currentTimeMillis()) - .setCategory(Notification.CATEGORY_SYSTEM) - .setPriority(Notification.PRIORITY_MAX) - .build(); - nm.notify(R.string.theme_reset_notification_title, notice); - } -} diff --git a/src/org/cyanogenmod/themeservice/ThemeManagerService.java b/src/org/cyanogenmod/themeservice/ThemeManagerService.java deleted file mode 100644 index 28ebc51..0000000 --- a/src/org/cyanogenmod/themeservice/ThemeManagerService.java +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * Copyright (C) 2016 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.cyanogenmod.themeservice; - -import android.app.ActivityManager; -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.app.WallpaperManager; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.ThemeConfig; -import android.media.RingtoneManager; -import android.os.Binder; -import android.os.Environment; -import android.os.FileUtils; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; - -import cyanogenmod.app.CMStatusBarManager; -import cyanogenmod.app.CustomTile; -import cyanogenmod.providers.CMSettings; -import cyanogenmod.providers.ThemesContract; -import cyanogenmod.themes.IThemeChangeListener; -import cyanogenmod.themes.IThemeProcessingListener; -import cyanogenmod.themes.IThemeService; -import cyanogenmod.themes.ThemeChangeRequest; - -import org.cyanogenmod.internal.util.ImageUtils; -import org.cyanogenmod.internal.util.QSConstants; -import org.cyanogenmod.internal.util.QSUtils; -import org.cyanogenmod.internal.util.ThemeUtils; - -import org.cyanogenmod.platform.internal.R; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import libcore.io.IoUtils; - -import static android.content.res.ThemeConfig.SYSTEM_DEFAULT; -import static cyanogenmod.platform.Manifest.permission.ACCESS_THEME_MANAGER; -import static org.cyanogenmod.internal.util.ThemeUtils.SYSTEM_THEME_PATH; -import static org.cyanogenmod.internal.util.ThemeUtils.THEME_BOOTANIMATION_PATH; - -public class ThemeManagerService extends Service { - private static final String TAG = ThemeManagerService.class.getSimpleName(); - private static final boolean DEBUG = false; - - private static final String GOOGLE_SETUPWIZARD_PACKAGE = "com.google.android.setupwizard"; - private static final String CM_SETUPWIZARD_PACKAGE = "com.cyanogenmod.setupwizard"; - private static final String MANAGED_PROVISIONING_PACKAGE = "com.android.managedprovisioning"; - - private static final String CATEGORY_THEME_CHOOSER = "cyanogenmod.intent.category.APP_THEMES"; - - // Defines a min and max compatible api level for themes on this system. - private static final int MIN_COMPATIBLE_VERSION = 21; - - private HandlerThread mWorker; - private ThemeWorkerHandler mHandler; - private ResourceProcessingHandler mResourceProcessingHandler; - private Context mContext; - private PackageManager mPM; - private int mProgress; - private boolean mWallpaperChangedByUs = false; - private int mCurrentUserId = UserHandle.USER_OWNER; - - private boolean mIsThemeApplying = false; - - private final RemoteCallbackList<IThemeChangeListener> mClients = new RemoteCallbackList<>(); - - private final RemoteCallbackList<IThemeProcessingListener> mProcessingListeners = - new RemoteCallbackList<>(); - - final private ArrayList<String> mThemesToProcessQueue = new ArrayList<>(); - - private long mLastThemeChangeTime = 0; - private int mLastThemeChangeRequestType; - - private class ThemeWorkerHandler extends Handler { - private static final int MESSAGE_CHANGE_THEME = 1; - private static final int MESSAGE_APPLY_DEFAULT_THEME = 2; - private static final int MESSAGE_REBUILD_RESOURCE_CACHE = 3; - - public ThemeWorkerHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_CHANGE_THEME: - final ThemeChangeRequest request = (ThemeChangeRequest) msg.obj; - doApplyTheme(request, msg.arg1 == 1); - break; - case MESSAGE_APPLY_DEFAULT_THEME: - doApplyDefaultTheme(); - break; - case MESSAGE_REBUILD_RESOURCE_CACHE: - doRebuildResourceCache(); - break; - default: - Log.w(TAG, "Unknown message " + msg.what); - break; - } - } - } - - private class ResourceProcessingHandler extends Handler { - private static final int MESSAGE_QUEUE_THEME_FOR_PROCESSING = 3; - private static final int MESSAGE_DEQUEUE_AND_PROCESS_THEME = 4; - - public ResourceProcessingHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_QUEUE_THEME_FOR_PROCESSING: - String pkgName = (String) msg.obj; - synchronized (mThemesToProcessQueue) { - if (!mThemesToProcessQueue.contains(pkgName)) { - if (DEBUG) Log.d(TAG, "Adding " + pkgName + " for processing"); - mThemesToProcessQueue.add(pkgName); - if (mThemesToProcessQueue.size() == 1) { - this.sendEmptyMessage(MESSAGE_DEQUEUE_AND_PROCESS_THEME); - } - } - } - break; - case MESSAGE_DEQUEUE_AND_PROCESS_THEME: - synchronized (mThemesToProcessQueue) { - pkgName = mThemesToProcessQueue.get(0); - } - if (pkgName != null) { - if (DEBUG) Log.d(TAG, "Processing " + pkgName); - String name; - try { - PackageInfo pi = mPM.getPackageInfo(pkgName, 0); - name = getThemeName(pi); - } catch (PackageManager.NameNotFoundException e) { - name = null; - } - - int result = mPM.processThemeResources(pkgName); - if (result < 0) { - postFailedThemeInstallNotification(name != null ? name : pkgName); - } - sendThemeResourcesCachedBroadcast(pkgName, result); - - synchronized (mThemesToProcessQueue) { - mThemesToProcessQueue.remove(0); - if (mThemesToProcessQueue.size() > 0 && - !hasMessages(MESSAGE_DEQUEUE_AND_PROCESS_THEME)) { - this.sendEmptyMessage(MESSAGE_DEQUEUE_AND_PROCESS_THEME); - } - } - postFinishedProcessing(pkgName); - } - break; - default: - Log.w(TAG, "Unknown message " + msg.what); - break; - } - } - } - - private IBinder mService = new IThemeService.Stub() { - @Override - public void requestThemeChangeUpdates(IThemeChangeListener listener) - throws RemoteException { - enforcePermission(); - mClients.register(listener); - } - - @Override - public void removeUpdates(IThemeChangeListener listener) throws RemoteException { - enforcePermission(); - mClients.unregister(listener); - } - - @Override - public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes) - throws RemoteException { - enforcePermission(); - Message msg; - - /** - * Since the ThemeService handles compiling theme resource we need to make sure that any - * of the components we are trying to apply are either already processed or put to the - * front of the queue and handled before the theme change takes place. - * - * TODO: create a callback that can be sent to any ThemeChangeListeners to notify them - * that the theme will be applied once the processing is done. - */ - synchronized (mThemesToProcessQueue) { - Map<String, String> componentMap = request.getThemeComponentsMap(); - for (Object key : componentMap.keySet()) { - if (ThemesContract.ThemesColumns.MODIFIES_OVERLAYS.equals(key) || - ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR.equals(key) || - ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR.equals(key) || - ThemesContract.ThemesColumns.MODIFIES_ICONS.equals(key)) { - String pkgName = componentMap.get(key); - if (mThemesToProcessQueue.indexOf(pkgName) > 0) { - mThemesToProcessQueue.remove(pkgName); - mThemesToProcessQueue.add(0, pkgName); - // We want to make sure these resources are taken care of first so - // send the dequeue message and place it in the front of the queue - msg = mResourceProcessingHandler.obtainMessage( - ResourceProcessingHandler.MESSAGE_DEQUEUE_AND_PROCESS_THEME); - mResourceProcessingHandler.sendMessageAtFrontOfQueue(msg); - } - } - } - } - msg = Message.obtain(); - msg.what = ThemeWorkerHandler.MESSAGE_CHANGE_THEME; - msg.obj = request; - msg.arg1 = removePerAppThemes ? 1 : 0; - mHandler.sendMessage(msg); - } - - @Override - public void applyDefaultTheme() { - enforcePermission(); - Message msg = Message.obtain(); - msg.what = ThemeWorkerHandler.MESSAGE_APPLY_DEFAULT_THEME; - mHandler.sendMessage(msg); - } - - @Override - public boolean isThemeApplying() throws RemoteException { - enforcePermission(); - return mIsThemeApplying; - } - - @Override - public int getProgress() throws RemoteException { - enforcePermission(); - synchronized(this) { - return mProgress; - } - } - - @Override - public boolean processThemeResources(String themePkgName) throws RemoteException { - enforcePermission(); - try { - mPM.getPackageInfo(themePkgName, 0); - } catch (PackageManager.NameNotFoundException e) { - // Package doesn't exist so nothing to process - return false; - } - // Obtain a message and send it to the handler to process this theme - Message msg = mResourceProcessingHandler.obtainMessage( - ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING, 0, 0, - themePkgName); - mResourceProcessingHandler.sendMessage(msg); - return true; - } - - @Override - public boolean isThemeBeingProcessed(String themePkgName) throws RemoteException { - enforcePermission(); - synchronized (mThemesToProcessQueue) { - return mThemesToProcessQueue.contains(themePkgName); - } - } - - @Override - public void registerThemeProcessingListener(IThemeProcessingListener listener) - throws RemoteException { - enforcePermission(); - mProcessingListeners.register(listener); - } - - @Override - public void unregisterThemeProcessingListener(IThemeProcessingListener listener) - throws RemoteException { - enforcePermission(); - mProcessingListeners.unregister(listener); - } - - @Override - public void rebuildResourceCache() throws RemoteException { - enforcePermission(); - mHandler.sendEmptyMessage(ThemeWorkerHandler.MESSAGE_REBUILD_RESOURCE_CACHE); - } - - @Override - public long getLastThemeChangeTime() { - return mLastThemeChangeTime; - } - - @Override - public int getLastThemeChangeRequestType() { - return mLastThemeChangeRequestType; - } - - private void enforcePermission() { - enforceCallingOrSelfPermission(ACCESS_THEME_MANAGER, null); - } - }; - - @Override - public IBinder onBind(Intent intent) { - return mService; - } - - @Override - public void onCreate() { - super.onCreate(); - mWorker = new HandlerThread("ThemeServiceWorker", Process.THREAD_PRIORITY_BACKGROUND); - mWorker.start(); - mHandler = new ThemeWorkerHandler(mWorker.getLooper()); - Log.i(TAG, "Spawned worker thread"); - - HandlerThread processingThread = new HandlerThread("ResourceProcessingThread", - Process.THREAD_PRIORITY_BACKGROUND); - processingThread.start(); - mResourceProcessingHandler = new ResourceProcessingHandler(processingThread.getLooper()); - - // create the theme directories if they do not exist - ThemeUtils.createThemeDirIfNotExists(); - ThemeUtils.createFontDirIfNotExists(); - ThemeUtils.createAlarmDirIfNotExists(); - ThemeUtils.createNotificationDirIfNotExists(); - ThemeUtils.createRingtoneDirIfNotExists(); - ThemeUtils.createIconCacheDirIfNotExists(); - - // listen for wallpaper changes - IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED); - registerReceiver(mWallpaperChangeReceiver, filter); - - filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); - registerReceiver(mUserChangeReceiver, filter); - - mPM = getPackageManager(); - - publishThemesTile(); - if (!isThemeApiUpToDate()) { - Log.d(TAG, "The system has been upgraded to a theme new api, " + - "checking if currently set theme is compatible"); - removeObsoleteThemeOverlayIfExists(); - updateThemeApi(); - } - registerAppsFailureReceiver(); - processInstalledThemes(); - } - - private void registerAppsFailureReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(cyanogenmod.content.Intent.ACTION_APP_FAILURE); - filter.addAction(ThemeUtils.ACTION_THEME_CHANGED); - registerReceiver(new AppsFailureReceiver(), filter); - } - - private void removeObsoleteThemeOverlayIfExists() { - // Get the current overlay theme so we can see it it's overlay should be unapplied - final IActivityManager am = ActivityManagerNative.getDefault(); - ThemeConfig config = null; - try { - if (am != null) { - config = am.getConfiguration().themeConfig; - } else { - Log.e(TAG, "ActivityManager getDefault() " + - "returned null, cannot remove obsolete theme"); - } - } catch(RemoteException e) { - Log.e(TAG, "Failed to get the theme config ", e); - } - if (config == null) return; // No need to unapply a theme if one isn't set - - // Populate the currentTheme map for the components we care about, we'll look - // at the compatibility of each pkg below. - HashMap<String, String> currentThemeMap = new HashMap<>(); - currentThemeMap.put(ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR, config.getOverlayForStatusBar()); - currentThemeMap.put(ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR, - config.getOverlayForNavBar()); - currentThemeMap.put(ThemesContract.ThemesColumns.MODIFIES_OVERLAYS, config.getOverlayPkgName()); - - // Look at each component's theme (that we care about at least) and check compatibility - // of the pkg with the system. If it is not compatible then we will add it to a theme - // change request. - Map<String, String> defaults = ThemeUtils.getDefaultComponents(this); - ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); - for(Map.Entry<String, String> entry : currentThemeMap.entrySet()) { - String component = entry.getKey(); - String pkgName = entry.getValue(); - String defaultPkg = defaults.get(component); - - if (defaultPkg == null) { - Log.d(TAG, "Default package is null, skipping " + component); - continue; - } - - // Check that the default overlay theme is not currently set - if (defaultPkg.equals(pkgName)) { - Log.d(TAG, "Current overlay theme is same as default. " + - "Not doing anything for " + component); - continue; - } - - // No need to unapply a system theme since it is always compatible - if (ThemeConfig.SYSTEM_DEFAULT.equals(pkgName)) { - Log.d(TAG, "Current overlay theme for " - + component + " was system. no need to unapply"); - continue; - } - - if (!isThemeCompatibleWithUpgradedApi(pkgName)) { - Log.d(TAG, pkgName + "is incompatible with latest theme api for component " + - component + ", Applying " + defaultPkg); - builder.setComponent(component, pkgName); - } - } - - // Now actually unapply the incompatible themes - ThemeChangeRequest request = builder.build(); - if (!request.getThemeComponentsMap().isEmpty()) { - try { - ((IThemeService) mService).requestThemeChange(request, true); - } catch(RemoteException e) { - // This cannot happen - } - } else { - Log.d(TAG, "Current theme is compatible with the system. Not unapplying anything"); - } - } - - private boolean isThemeCompatibleWithUpgradedApi(String pkgName) { - // Note this function does not cover the case of a downgrade. That case is out of scope and - // would require predicting whether the future API levels will be compatible or not. - boolean compatible = false; - try { - PackageInfo pi = mPM.getPackageInfo(pkgName, 0); - Log.d(TAG, "Comparing theme target: " + pi.applicationInfo.targetSdkVersion + - "to " + android.os.Build.VERSION.SDK_INT); - compatible = pi.applicationInfo.targetSdkVersion >= MIN_COMPATIBLE_VERSION; - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Unable to get package info for " + pkgName, e); - } - return compatible; - } - - private boolean isThemeApiUpToDate() { - // We can't be 100% sure its an upgrade. If the field is undefined it - // could have been a factory reset. - final ContentResolver resolver = getContentResolver(); - int recordedApiLevel = android.os.Build.VERSION.SDK_INT; - try { - recordedApiLevel = CMSettings.Secure.getInt(resolver, - CMSettings.Secure.THEME_PREV_BOOT_API_LEVEL); - } catch (CMSettings.CMSettingNotFoundException e) { - recordedApiLevel = -1; - Log.d(TAG, "Previous api level not found. First time booting?"); - } - Log.d(TAG, "Prev api level was: " + recordedApiLevel - + ", api is now: " + android.os.Build.VERSION.SDK_INT); - - return recordedApiLevel == android.os.Build.VERSION.SDK_INT; - } - - private void updateThemeApi() { - final ContentResolver resolver = getContentResolver(); - boolean success = CMSettings.Secure.putInt(resolver, - CMSettings.Secure.THEME_PREV_BOOT_API_LEVEL, android.os.Build.VERSION.SDK_INT); - if (!success) { - Log.e(TAG, "Unable to store latest API level to secure settings"); - } - } - - private void doApplyTheme(ThemeChangeRequest request, boolean removePerAppTheme) { - synchronized(this) { - mProgress = 0; - } - - if (request == null || request.getNumChangesRequested() == 0) { - postFinish(true, request, 0); - return; - } - mIsThemeApplying = true; - mLastThemeChangeTime = System.currentTimeMillis(); - mLastThemeChangeRequestType = request.getReqeustType().ordinal(); - - incrementProgress(5); - - // TODO: provide progress updates that reflect the time needed for each component - final int progressIncrement = 75 / request.getNumChangesRequested(); - - if (request.getIconsThemePackageName() != null) { - updateIcons(request.getIconsThemePackageName()); - incrementProgress(progressIncrement); - } - - if (request.getWallpaperThemePackageName() != null) { - if (updateWallpaper(request.getWallpaperThemePackageName(), - request.getWallpaperId())) { - mWallpaperChangedByUs = true; - } - incrementProgress(progressIncrement); - } - - if (request.getLockWallpaperThemePackageName() != null) { - updateLockscreen(request.getLockWallpaperThemePackageName()); - incrementProgress(progressIncrement); - } - - Environment.setUserRequired(false); - if (request.getNotificationThemePackageName() != null) { - updateNotifications(request.getNotificationThemePackageName()); - incrementProgress(progressIncrement); - } - - if (request.getAlarmThemePackageName() != null) { - updateAlarms(request.getAlarmThemePackageName()); - incrementProgress(progressIncrement); - } - - if (request.getRingtoneThemePackageName() != null) { - updateRingtones(request.getRingtoneThemePackageName()); - incrementProgress(progressIncrement); - } - Environment.setUserRequired(true); - - if (request.getBootanimationThemePackageName() != null) { - updateBootAnim(request.getBootanimationThemePackageName()); - incrementProgress(progressIncrement); - } - - if (request.getFontThemePackageName() != null) { - updateFonts(request.getFontThemePackageName()); - incrementProgress(progressIncrement); - } - - if (request.getLiveLockScreenThemePackageName() != null) { - updateLiveLockScreen(request.getLiveLockScreenThemePackageName()); - incrementProgress(progressIncrement); - } - - try { - updateProvider(request, mLastThemeChangeTime); - } catch(IllegalArgumentException e) { - // Safeguard against provider not being ready yet. - Log.e(TAG, "Not updating the theme provider since it is unavailable"); - } - - if (shouldUpdateConfiguration(request)) { - updateConfiguration(request, removePerAppTheme); - } - - killLaunchers(request); - - postFinish(true, request, mLastThemeChangeTime); - mIsThemeApplying = false; - } - - private void doApplyDefaultTheme() { - final ContentResolver resolver = getContentResolver(); - final String defaultThemePkg = ThemeUtils.getDefaultThemePackageName(this); - if (!TextUtils.isEmpty(defaultThemePkg)) { - String defaultThemeComponents = CMSettings.Secure.getString(resolver, - CMSettings.Secure.DEFAULT_THEME_COMPONENTS); - List<String> components; - if (TextUtils.isEmpty(defaultThemeComponents)) { - components = ThemeUtils.getAllComponents(); - } else { - components = new ArrayList<String>( - Arrays.asList(defaultThemeComponents.split("\\|"))); - } - ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); - for (String component : components) { - builder.setComponent(component, defaultThemePkg); - } - try { - ((IThemeService) mService).requestThemeChange(builder.build(), true); - } catch (RemoteException e) { - Log.w(TAG, "Unable to set default theme", e); - } - } - } - - private void doRebuildResourceCache() { - FileUtils.deleteContents(new File(ThemeUtils.RESOURCE_CACHE_DIR)); - processInstalledThemes(); - } - - private void updateProvider(ThemeChangeRequest request, long updateTime) { - ContentValues values = new ContentValues(); - values.put(ThemesContract.MixnMatchColumns.COL_UPDATE_TIME, updateTime); - Map<String, String> componentMap = request.getThemeComponentsMap(); - for (String component : componentMap.keySet()) { - values.put(ThemesContract.MixnMatchColumns.COL_VALUE, componentMap.get(component)); - String where = ThemesContract.MixnMatchColumns.COL_KEY + "=?"; - String[] selectionArgs = { ThemesContract.MixnMatchColumns.componentToMixNMatchKey(component) }; - if (selectionArgs[0] == null) { - continue; // No equivalence between mixnmatch and theme - } - - // Add component ID for multiwallpaper - if (ThemesContract.ThemesColumns.MODIFIES_LAUNCHER.equals(component)) { - values.put(ThemesContract.MixnMatchColumns.COL_COMPONENT_ID, request.getWallpaperId()); - } - - getContentResolver().update(ThemesContract.MixnMatchColumns.CONTENT_URI, values, where, - selectionArgs); - } - } - - private boolean updateIcons(String pkgName) { - ThemeUtils.clearIconCache(); - try { - if (pkgName.equals(SYSTEM_DEFAULT)) { - mPM.updateIconMaps(null); - } else { - mPM.updateIconMaps(pkgName); - } - } catch (Exception e) { - Log.w(TAG, "Changing icons failed", e); - return false; - } - return true; - } - - private boolean updateFonts(String pkgName) { - //Clear the font dir - FileUtils.deleteContents(new File(ThemeUtils.SYSTEM_THEME_FONT_PATH)); - - if (!pkgName.equals(SYSTEM_DEFAULT)) { - //Get Font Assets - Context themeCtx; - String[] assetList; - try { - themeCtx = createPackageContext(pkgName, Context.CONTEXT_IGNORE_SECURITY); - AssetManager assetManager = themeCtx.getAssets(); - assetList = assetManager.list("fonts"); - } catch (Exception e) { - Log.e(TAG, "There was an error getting assets for pkg " + pkgName, e); - return false; - } - if (assetList == null || assetList.length == 0) { - Log.e(TAG, "Could not find any font assets"); - return false; - } - - //Copy font assets to font dir - for(String asset : assetList) { - InputStream is = null; - OutputStream os = null; - try { - is = ThemeUtils.getInputStreamFromAsset(themeCtx, - "file:///android_asset/fonts/" + asset); - File outFile = new File(ThemeUtils.SYSTEM_THEME_FONT_PATH, asset); - FileUtils.copyToFile(is, outFile); - FileUtils.setPermissions(outFile, - FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IRWXO, -1, -1); - } catch (Exception e) { - Log.e(TAG, "There was an error installing the new fonts for pkg " + pkgName, e); - return false; - } finally { - IoUtils.closeQuietly(is); - IoUtils.closeQuietly(os); - } - } - } - - //Notify zygote that themes need a refresh - SystemProperties.set("sys.refresh_theme", "1"); - return true; - } - - private boolean updateBootAnim(String pkgName) { - if (TextUtils.isEmpty(pkgName) || SYSTEM_DEFAULT.equals(pkgName)) { - clearBootAnimation(); - return true; - } - - try { - final ApplicationInfo ai = mPM.getApplicationInfo(pkgName, 0); - applyBootAnimation(ai.sourceDir); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Changing boot animation failed", e); - return false; - } - return true; - } - - private boolean updateAlarms(String pkgName) { - return updateAudible(ThemeUtils.SYSTEM_THEME_ALARM_PATH, "alarms", - RingtoneManager.TYPE_ALARM, pkgName); - } - - private boolean updateNotifications(String pkgName) { - return updateAudible(ThemeUtils.SYSTEM_THEME_NOTIFICATION_PATH, "notifications", - RingtoneManager.TYPE_NOTIFICATION, pkgName); - } - - private boolean updateRingtones(String pkgName) { - return updateAudible(ThemeUtils.SYSTEM_THEME_RINGTONE_PATH, "ringtones", - RingtoneManager.TYPE_RINGTONE, pkgName); - } - - private boolean updateAudible(String dirPath, String assetPath, int type, String pkgName) { - //Clear the dir - ThemeUtils.clearAudibles(this, dirPath); - if (TextUtils.isEmpty(pkgName) || pkgName.equals(SYSTEM_DEFAULT)) { - if (!ThemeUtils.setDefaultAudible(this, type)) { - Log.e(TAG, "There was an error installing the default audio file"); - return false; - } - return true; - } - - PackageInfo pi = null; - try { - pi = mPM.getPackageInfo(pkgName, 0); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Unable to update audible " + dirPath, e); - return false; - } - - //Get theme Assets - Context themeCtx; - String[] assetList; - try { - themeCtx = createPackageContext(pkgName, Context.CONTEXT_IGNORE_SECURITY); - AssetManager assetManager = themeCtx.getAssets(); - assetList = assetManager.list(assetPath); - } catch (Exception e) { - Log.e(TAG, "There was an error getting assets for pkg " + pkgName, e); - return false; - } - if (assetList == null || assetList.length == 0) { - Log.e(TAG, "Could not find any audio assets"); - return false; - } - - // TODO: right now we just load the first file but this will need to be changed - // in the future if multiple audio files are supported. - final String asset = assetList[0]; - if (!ThemeUtils.isValidAudible(asset)) return false; - - InputStream is = null; - OutputStream os = null; - try { - is = ThemeUtils.getInputStreamFromAsset(themeCtx, "file:///android_asset/" - + assetPath + File.separator + asset); - File outFile = new File(dirPath, asset); - FileUtils.copyToFile(is, outFile); - FileUtils.setPermissions(outFile, - FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IRWXO,-1, -1); - ThemeUtils.setAudible(this, outFile, type, pi.themeInfo.name); - } catch (Exception e) { - Log.e(TAG, "There was an error installing the new audio file for pkg " + pkgName, e); - return false; - } finally { - IoUtils.closeQuietly(is); - IoUtils.closeQuietly(os); - } - return true; - } - - private boolean updateLockscreen(String pkgName) { - boolean success; - success = setCustomLockScreenWallpaper(pkgName); - - if (success) { - sendBroadcastAsUser(new Intent(Intent.ACTION_KEYGUARD_WALLPAPER_CHANGED), - UserHandle.ALL); - } - return success; - } - - private boolean setCustomLockScreenWallpaper(String pkgName) { - WallpaperManager wm = WallpaperManager.getInstance(this); - try { - if (SYSTEM_DEFAULT.equals(pkgName) || TextUtils.isEmpty(pkgName)) { - wm.clearKeyguardWallpaper(); - } else { - InputStream in = ImageUtils.getCroppedKeyguardStream(pkgName, this); - if (in != null) { - wm.setKeyguardStream(in); - IoUtils.closeQuietly(in); - } - } - } catch (Exception e) { - Log.e(TAG, "There was an error setting lockscreen wp for pkg " + pkgName, e); - return false; - } - return true; - } - - private boolean updateWallpaper(String pkgName, long id) { - WallpaperManager wm = WallpaperManager.getInstance(this); - if (SYSTEM_DEFAULT.equals(pkgName)) { - try { - wm.clear(); - } catch (IOException e) { - return false; - } - } else if (TextUtils.isEmpty(pkgName)) { - try { - wm.clear(false); - } catch (IOException e) { - return false; - } - } else { - InputStream in = null; - try { - in = ImageUtils.getCroppedWallpaperStream(pkgName, id, this); - if (in != null) - wm.setStream(in); - } catch (Exception e) { - return false; - } finally { - IoUtils.closeQuietly(in); - } - } - return true; - } - - private boolean updateLiveLockScreen(String pkgName) { - // TODO: do something meaningful here once ready - return true; - } - - private boolean updateConfiguration(ThemeChangeRequest request, - boolean removePerAppThemes) { - final IActivityManager am = ActivityManagerNative.getDefault(); - if (am != null) { - final long token = Binder.clearCallingIdentity(); - try { - Configuration config = am.getConfiguration(); - ThemeConfig.Builder themeBuilder = createBuilderFrom(config, request, null, - removePerAppThemes); - ThemeConfig newConfig = themeBuilder.build(); - - config.themeConfig = newConfig; - am.updateConfiguration(config); - } catch (RemoteException e) { - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - return true; - } - - private boolean updateConfiguration(ThemeConfig themeConfig) { - final IActivityManager am = ActivityManagerNative.getDefault(); - if (am != null) { - final long token = Binder.clearCallingIdentity(); - try { - Configuration config = am.getConfiguration(); - - config.themeConfig = themeConfig; - am.updateConfiguration(config); - } catch (RemoteException e) { - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - return true; - } - - private boolean shouldUpdateConfiguration(ThemeChangeRequest request) { - return request.getOverlayThemePackageName() != null || - request.getFontThemePackageName() != null || - request.getIconsThemePackageName() != null || - request.getStatusBarThemePackageName() != null || - request.getNavBarThemePackageName() != null || - request.getPerAppOverlays().size() > 0; - } - - private static ThemeConfig.Builder createBuilderFrom(Configuration config, - ThemeChangeRequest request, String pkgName, boolean removePerAppThemes) { - ThemeConfig.Builder builder = new ThemeConfig.Builder(config.themeConfig); - - if (removePerAppThemes) removePerAppThemesFromConfig(builder, config.themeConfig); - - if (request.getIconsThemePackageName() != null) { - builder.defaultIcon(pkgName == null ? request.getIconsThemePackageName() : pkgName); - } - - if (request.getOverlayThemePackageName() != null) { - builder.defaultOverlay(pkgName == null ? - request.getOverlayThemePackageName() : pkgName); - } - - if (request.getFontThemePackageName() != null) { - builder.defaultFont(pkgName == null ? request.getFontThemePackageName() : pkgName); - } - - if (request.getStatusBarThemePackageName() != null) { - builder.overlay(ThemeConfig.SYSTEMUI_STATUS_BAR_PKG, pkgName == null ? - request.getStatusBarThemePackageName() : pkgName); - } - - if (request.getNavBarThemePackageName() != null) { - builder.overlay(ThemeConfig.SYSTEMUI_NAVBAR_PKG, pkgName == null ? - request.getNavBarThemePackageName() : pkgName); - } - - // check for any per app overlays being applied - Map<String, String> appOverlays = request.getPerAppOverlays(); - for (String appPkgName : appOverlays.keySet()) { - if (appPkgName != null) { - builder.overlay(appPkgName, appOverlays.get(appPkgName)); - } - } - - return builder; - } - - private static void removePerAppThemesFromConfig(ThemeConfig.Builder builder, - ThemeConfig themeConfig) { - if (themeConfig != null) { - Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes(); - for (String appPkgName : themes.keySet()) { - if (ThemeUtils.isPerAppThemeComponent(appPkgName)) { - builder.overlay(appPkgName, null); - } - } - } - } - - // Kill the current Home process, they tend to be evil and cache - // drawable references in all apps - private void killLaunchers(ThemeChangeRequest request) { - if (request.getOverlayThemePackageName() == null - && request.getIconsThemePackageName() == null) { - return; - } - - final ActivityManager am = - (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - - Intent homeIntent = new Intent(); - homeIntent.setAction(Intent.ACTION_MAIN); - homeIntent.addCategory(Intent.CATEGORY_HOME); - - List<ResolveInfo> infos = mPM.queryIntentActivities(homeIntent, 0); - List<ResolveInfo> themeChangeInfos = mPM.queryBroadcastReceivers( - new Intent(ThemeUtils.ACTION_THEME_CHANGED), 0); - for(ResolveInfo info : infos) { - if (info.activityInfo != null && info.activityInfo.applicationInfo != null && - !isSetupActivity(info) && !handlesThemeChanges( - info.activityInfo.applicationInfo.packageName, themeChangeInfos)) { - String pkgToStop = info.activityInfo.applicationInfo.packageName; - Log.d(TAG, "Force stopping " + pkgToStop + " for theme change"); - try { - am.forceStopPackage(pkgToStop); - } catch(Exception e) { - Log.e(TAG, "Unable to force stop package, did you forget platform signature?", - e); - } - } - } - } - - private boolean isSetupActivity(ResolveInfo info) { - return GOOGLE_SETUPWIZARD_PACKAGE.equals(info.activityInfo.packageName) || - MANAGED_PROVISIONING_PACKAGE.equals(info.activityInfo.packageName) || - CM_SETUPWIZARD_PACKAGE.equals(info.activityInfo.packageName); - } - - private boolean handlesThemeChanges(String pkgName, List<ResolveInfo> infos) { - if (infos != null && infos.size() > 0) { - for (ResolveInfo info : infos) { - if (info.activityInfo.applicationInfo.packageName.equals(pkgName)) { - return true; - } - } - } - return false; - } - - private void postProgress() { - int N = mClients.beginBroadcast(); - for(int i=0; i < N; i++) { - IThemeChangeListener listener = mClients.getBroadcastItem(0); - try { - listener.onProgress(mProgress); - } catch(RemoteException e) { - Log.w(TAG, "Unable to post progress to client listener", e); - } - } - mClients.finishBroadcast(); - } - - private void postFinish(boolean isSuccess, ThemeChangeRequest request, long updateTime) { - synchronized(this) { - mProgress = 0; - } - - int N = mClients.beginBroadcast(); - for(int i=0; i < N; i++) { - IThemeChangeListener listener = mClients.getBroadcastItem(0); - try { - listener.onFinish(isSuccess); - } catch(RemoteException e) { - Log.w(TAG, "Unable to post progress to client listener", e); - } - } - mClients.finishBroadcast(); - - // if successful, broadcast that the theme changed - if (isSuccess) { - broadcastThemeChange(request, updateTime); - } - } - - private void postFinishedProcessing(String pkgName) { - int N = mProcessingListeners.beginBroadcast(); - for(int i=0; i < N; i++) { - IThemeProcessingListener listener = mProcessingListeners.getBroadcastItem(0); - try { - listener.onFinishedProcessing(pkgName); - } catch(RemoteException e) { - Log.w(TAG, "Unable to post progress to listener", e); - } - } - mProcessingListeners.finishBroadcast(); - } - - private void broadcastThemeChange(ThemeChangeRequest request, long updateTime) { - Map<String, String> componentMap = request.getThemeComponentsMap(); - if (componentMap == null || componentMap.size() == 0) return; - - final Intent intent = new Intent(ThemeUtils.ACTION_THEME_CHANGED); - ArrayList componentsArrayList = new ArrayList(componentMap.keySet()); - intent.putStringArrayListExtra(ThemeUtils.EXTRA_COMPONENTS, componentsArrayList); - intent.putExtra(ThemeUtils.EXTRA_REQUEST_TYPE, request.getReqeustType().ordinal()); - intent.putExtra(ThemeUtils.EXTRA_UPDATE_TIME, updateTime); - sendBroadcastAsUser(intent, UserHandle.ALL); - } - - private void incrementProgress(int increment) { - synchronized(this) { - mProgress += increment; - if (mProgress > 100) mProgress = 100; - } - postProgress(); - } - - private boolean applyBootAnimation(String themePath) { - boolean success = false; - try { - ZipFile zip = new ZipFile(new File(themePath)); - ZipEntry ze = zip.getEntry(THEME_BOOTANIMATION_PATH); - if (ze != null) { - clearBootAnimation(); - BufferedInputStream is = new BufferedInputStream(zip.getInputStream(ze)); - final String bootAnimationPath = SYSTEM_THEME_PATH + File.separator - + "bootanimation.zip"; - ThemeUtils.copyAndScaleBootAnimation(this, is, bootAnimationPath); - FileUtils.setPermissions(bootAnimationPath, - FileUtils.S_IRWXU|FileUtils.S_IRGRP|FileUtils.S_IROTH, -1, -1); - } - zip.close(); - success = true; - } catch (Exception e) { - Log.w(TAG, "Unable to load boot animation for " + themePath, e); - } - - return success; - } - - private void clearBootAnimation() { - File anim = new File(SYSTEM_THEME_PATH + File.separator + "bootanimation.zip"); - if (anim.exists()) - anim.delete(); - } - - private BroadcastReceiver mWallpaperChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!mWallpaperChangedByUs) { - // In case the mixnmatch table has a mods_launcher entry, we'll clear it - ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); - builder.setWallpaper(""); - updateProvider(builder.build(), System.currentTimeMillis()); - } else { - mWallpaperChangedByUs = false; - } - } - }; - - private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - if (userHandle >= 0 && userHandle != mCurrentUserId) { - mCurrentUserId = userHandle; - ThemeConfig config = ThemeConfig.getBootThemeForUser(getContentResolver(), - userHandle); - if (DEBUG) { - Log.d(TAG, - "Changing theme for user " + userHandle + " to " + config.toString()); - } - ThemeChangeRequest request = new ThemeChangeRequest.Builder(config).build(); - try { - ((IThemeService) mService).requestThemeChange(request, true); - } catch (RemoteException e) { - Log.e(TAG, "Unable to change theme for user change", e); - } - } - } - }; - - private void processInstalledThemes() { - final String defaultTheme = getDefaultThemePackageName(this); - Message msg; - // Make sure the default theme is the first to get processed! - if (!ThemeConfig.SYSTEM_DEFAULT.equals(defaultTheme)) { - msg = mHandler.obtainMessage( - ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING, - 0, 0, defaultTheme); - mResourceProcessingHandler.sendMessage(msg); - } - // Iterate over all installed packages and queue up the ones that are themes or icon packs - List<PackageInfo> packages = mPM.getInstalledPackages(0); - for (PackageInfo info : packages) { - if (!defaultTheme.equals(info.packageName) && - (info.isThemeApk || info.isLegacyIconPackApk)) { - msg = mHandler.obtainMessage( - ResourceProcessingHandler.MESSAGE_QUEUE_THEME_FOR_PROCESSING, - 0, 0, info.packageName); - mResourceProcessingHandler.sendMessage(msg); - } - } - } - - private void sendThemeResourcesCachedBroadcast(String themePkgName, int resultCode) { - final Intent intent = new Intent(Intent.ACTION_THEME_RESOURCES_CACHED); - intent.putExtra(Intent.EXTRA_THEME_PACKAGE_NAME, themePkgName); - intent.putExtra(Intent.EXTRA_THEME_RESULT, resultCode); - sendBroadcastAsUser(intent, UserHandle.ALL); - } - - /** - * Posts a notification to let the user know the theme was not installed. - * @param name - */ - private void postFailedThemeInstallNotification(String name) { - NotificationManager nm = - (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - Notification notice = new Notification.Builder(this) - .setAutoCancel(true) - .setOngoing(false) - .setContentTitle( - getString(R.string.theme_install_error_title)) - .setContentText(String.format( - getString(R.string.theme_install_error_message), name)) - .setSmallIcon(android.R.drawable.stat_notify_error) - .setWhen(System.currentTimeMillis()) - .build(); - nm.notify(name.hashCode(), notice); - } - - private String getThemeName(PackageInfo pi) { - if (pi.themeInfo != null) { - return pi.themeInfo.name; - } else if (pi.isLegacyIconPackApk) { - return pi.applicationInfo.name; - } - - return null; - } - - /** - * Get the default theme package name - * Historically this was done using {@link ThemeUtils#getDefaultThemePackageName(Context)} but - * the setting that is queried in that method uses the AOSP settings provider but the setting - * is now in CMSettings. Since {@link ThemeUtils} is in the core framework we cannot access - * CMSettings. - * @param context - * @return Default theme package name - */ - private static String getDefaultThemePackageName(Context context) { - final String defaultThemePkg = CMSettings.Secure.getString(context.getContentResolver(), - CMSettings.Secure.DEFAULT_THEME_PACKAGE); - if (!TextUtils.isEmpty(defaultThemePkg)) { - PackageManager pm = context.getPackageManager(); - try { - if (pm.getPackageInfo(defaultThemePkg, 0) != null) { - return defaultThemePkg; - } - } catch (PackageManager.NameNotFoundException e) { - // doesn't exist so system will be default - Log.w(TAG, "Default theme " + defaultThemePkg + " not found", e); - } - } - - return SYSTEM_DEFAULT; - } - - private void publishThemesTile() { - // This action should be performed as system - final int userId = UserHandle.myUserId(); - long token = Binder.clearCallingIdentity(); - try { - final UserHandle user = new UserHandle(userId); - final Context resourceContext = QSUtils.getQSTileContext(this, userId); - - CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(this); - final PendingIntent chooserIntent = getThemeChooserPendingIntent(); - CustomTile tile = new CustomTile.Builder(resourceContext) - .setLabel(R.string.qs_themes_label) - .setContentDescription(R.string.qs_themes_content_description) - .setIcon(R.drawable.ic_qs_themes) - .setOnClickIntent(chooserIntent) - .setOnLongClickIntent(chooserIntent) - .shouldCollapsePanel(true) - .build(); - statusBarManager.publishTileAsUser(QSConstants.DYNAMIC_TILE_THEMES, - ThemeManagerService.class.hashCode(), tile, user); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private PendingIntent getThemeChooserPendingIntent() { - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(CATEGORY_THEME_CHOOSER); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - return PendingIntent.getActivity(this, ThemeManagerService.class.hashCode(), - intent, 0); - } - -} |