Themes: Refactor themes to CMSDK [2/6]
First attempt at moving as much as possible out of F/B and into cmsdk Change-Id: I9e53d1c32e01e88fc3918663dabe0001df922bc2 TICKET: CYNGNOS-2126
This commit is contained in:
parent
567b43017a
commit
b3ea2859fd
@ -371,8 +371,13 @@ package cyanogenmod.content {
|
||||
ctor public Intent();
|
||||
field public static final java.lang.String ACTION_PROTECTED = "cyanogenmod.intent.action.PACKAGE_PROTECTED";
|
||||
field public static final java.lang.String ACTION_PROTECTED_CHANGED = "cyanogenmod.intent.action.PROTECTED_COMPONENT_UPDATE";
|
||||
field public static final java.lang.String ACTION_THEME_INSTALLED = "cyanogenmod.intent.action.THEME_INSTALLED";
|
||||
field public static final java.lang.String ACTION_THEME_REMOVED = "cyanogenmod.intent.action.THEME_REMOVED";
|
||||
field public static final java.lang.String ACTION_THEME_UPDATED = "cyanogenmod.intent.action.THEME_UPDATED";
|
||||
field public static final java.lang.String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE = "cyanogenmod.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE";
|
||||
field public static final java.lang.String EXTRA_PROTECTED_COMPONENTS = "cyanogenmod.intent.extra.PACKAGE_PROTECTED_COMPONENTS";
|
||||
field public static final java.lang.String EXTRA_PROTECTED_STATE = "cyanogenmod.intent.extra.PACKAGE_PROTECTED_STATE";
|
||||
field public static final java.lang.String URI_SCHEME_PACKAGE = "package";
|
||||
}
|
||||
|
||||
}
|
||||
@ -556,6 +561,7 @@ package cyanogenmod.platform {
|
||||
public static final class Manifest.permission {
|
||||
ctor public Manifest.permission();
|
||||
field public static final java.lang.String ACCESS_APP_SUGGESTIONS = "cyanogenmod.permission.ACCESS_APP_SUGGESTIONS";
|
||||
field public static final java.lang.String ACCESS_THEME_MANAGER = "cyanogenmod.permission.ACCESS_THEME_MANAGER";
|
||||
field public static final java.lang.String HARDWARE_ABSTRACTION_ACCESS = "cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS";
|
||||
field public static final java.lang.String MANAGE_ALARMS = "cyanogenmod.permission.MANAGE_ALARMS";
|
||||
field public static final java.lang.String MANAGE_PERSISTENT_STORAGE = "cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE";
|
||||
@ -567,10 +573,12 @@ package cyanogenmod.platform {
|
||||
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
||||
field public static final java.lang.String READ_ALARMS = "cyanogenmod.permission.READ_ALARMS";
|
||||
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
||||
field public static final java.lang.String READ_THEMES = "cyanogenmod.permission.READ_THEMES";
|
||||
field public static final java.lang.String THIRD_PARTY_KEYGUARD = "android.permission.THIRD_PARTY_KEYGUARD";
|
||||
field public static final java.lang.String WRITE_ALARMS = "cyanogenmod.permission.WRITE_ALARMS";
|
||||
field public static final java.lang.String WRITE_SECURE_SETTINGS = "cyanogenmod.permission.WRITE_SECURE_SETTINGS";
|
||||
field public static final java.lang.String WRITE_SETTINGS = "cyanogenmod.permission.WRITE_SETTINGS";
|
||||
field public static final java.lang.String WRITE_THEMES = "cyanogenmod.permission.WRITE_THEMES";
|
||||
}
|
||||
|
||||
public final class R {
|
||||
@ -878,6 +886,126 @@ package cyanogenmod.providers {
|
||||
field public static final java.lang.String ZEN_PRIORITY_ALLOW_LIGHTS = "zen_priority_allow_lights";
|
||||
}
|
||||
|
||||
public class ThemesContract {
|
||||
ctor public ThemesContract();
|
||||
field public static final java.lang.String AUTHORITY = "com.cyanogenmod.themes";
|
||||
field public static final android.net.Uri AUTHORITY_URI;
|
||||
}
|
||||
|
||||
public static class ThemesContract.MixnMatchColumns {
|
||||
ctor public ThemesContract.MixnMatchColumns();
|
||||
method public static java.lang.String componentToImageColName(java.lang.String);
|
||||
method public static java.lang.String componentToMixNMatchKey(java.lang.String);
|
||||
method public static java.lang.String mixNMatchKeyToComponent(java.lang.String);
|
||||
field public static final java.lang.String COL_COMPONENT_ID = "component_id";
|
||||
field public static final java.lang.String COL_KEY = "key";
|
||||
field public static final java.lang.String COL_PREV_VALUE = "previous_value";
|
||||
field public static final java.lang.String COL_UPDATE_TIME = "update_time";
|
||||
field public static final java.lang.String COL_VALUE = "value";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String KEY_ALARM = "mixnmatch_alarm";
|
||||
field public static final java.lang.String KEY_BOOT_ANIM = "mixnmatch_boot_anim";
|
||||
field public static final java.lang.String KEY_FONT = "mixnmatch_font";
|
||||
field public static final java.lang.String KEY_HOMESCREEN = "mixnmatch_homescreen";
|
||||
field public static final java.lang.String KEY_ICONS = "mixnmatch_icons";
|
||||
field public static final java.lang.String KEY_LIVE_LOCK_SCREEN = "mixnmatch_live_lock_screen";
|
||||
field public static final java.lang.String KEY_LOCKSCREEN = "mixnmatch_lockscreen";
|
||||
field public static final java.lang.String KEY_NAVIGATION_BAR = "mixnmatch_navigation_bar";
|
||||
field public static final java.lang.String KEY_NOTIFICATIONS = "mixnmatch_notifications";
|
||||
field public static final java.lang.String KEY_OVERLAYS = "mixnmatch_overlays";
|
||||
field public static final java.lang.String KEY_RINGTONE = "mixnmatch_ringtone";
|
||||
field public static final java.lang.String KEY_STATUS_BAR = "mixnmatch_status_bar";
|
||||
field public static final java.lang.String[] ROWS;
|
||||
}
|
||||
|
||||
public static class ThemesContract.PreviewColumns {
|
||||
ctor public ThemesContract.PreviewColumns();
|
||||
field public static final android.net.Uri APPLIED_URI;
|
||||
field public static final java.lang.String BOOTANIMATION_THUMBNAIL = "bootanimation_thumbnail";
|
||||
field public static final java.lang.String COL_KEY = "key";
|
||||
field public static final java.lang.String COL_VALUE = "value";
|
||||
field public static final android.net.Uri COMPONENTS_URI;
|
||||
field public static final java.lang.String COMPONENT_ID = "component_id";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String ICON_PREVIEW_1 = "icon_preview_1";
|
||||
field public static final java.lang.String ICON_PREVIEW_2 = "icon_preview_2";
|
||||
field public static final java.lang.String ICON_PREVIEW_3 = "icon_preview_3";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_PREVIEW = "live_lock_screen_preview";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_THUMBNAIL = "live_lock_screen_thumbnail";
|
||||
field public static final java.lang.String LOCK_WALLPAPER_PREVIEW = "lock_wallpaper_preview";
|
||||
field public static final java.lang.String LOCK_WALLPAPER_THUMBNAIL = "lock_wallpaper_thumbnail";
|
||||
field public static final java.lang.String NAVBAR_BACKGROUND = "navbar_background";
|
||||
field public static final java.lang.String NAVBAR_BACK_BUTTON = "navbar_back_button";
|
||||
field public static final java.lang.String NAVBAR_HOME_BUTTON = "navbar_home_button";
|
||||
field public static final java.lang.String NAVBAR_RECENT_BUTTON = "navbar_recent_button";
|
||||
field public static final java.lang.String STATUSBAR_BACKGROUND = "statusbar_background";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_CIRCLE = "statusbar_battery_circle";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_LANDSCAPE = "statusbar_battery_landscape";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_PORTRAIT = "statusbar_battery_portrait";
|
||||
field public static final java.lang.String STATUSBAR_BLUETOOTH_ICON = "statusbar_bluetooth_icon";
|
||||
field public static final java.lang.String STATUSBAR_CLOCK_TEXT_COLOR = "statusbar_clock_text_color";
|
||||
field public static final java.lang.String STATUSBAR_SIGNAL_ICON = "statusbar_signal_icon";
|
||||
field public static final java.lang.String STATUSBAR_WIFI_COMBO_MARGIN_END = "wifi_combo_margin_end";
|
||||
field public static final java.lang.String STATUSBAR_WIFI_ICON = "statusbar_wifi_icon";
|
||||
field public static final java.lang.String STYLE_PREVIEW = "style_preview";
|
||||
field public static final java.lang.String STYLE_THUMBNAIL = "style_thumbnail";
|
||||
field public static final java.lang.String THEME_ID = "theme_id";
|
||||
field public static final java.lang.String[] VALID_KEYS;
|
||||
field public static final java.lang.String WALLPAPER_FULL = "wallpaper_full";
|
||||
field public static final java.lang.String WALLPAPER_PREVIEW = "wallpaper_preview";
|
||||
field public static final java.lang.String WALLPAPER_THUMBNAIL = "wallpaper_thumbnail";
|
||||
field public static final java.lang.String _ID = "_id";
|
||||
}
|
||||
|
||||
public static class ThemesContract.ThemesColumns {
|
||||
ctor public ThemesContract.ThemesColumns();
|
||||
field public static final java.lang.String AUTHOR = "author";
|
||||
field public static final java.lang.String BOOT_ANIM_URI = "bootanim_uri";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String DATE_CREATED = "created";
|
||||
field public static final java.lang.String FONT_URI = "font_uri";
|
||||
field public static final java.lang.String HOMESCREEN_URI = "homescreen_uri";
|
||||
field public static final java.lang.String ICON_URI = "icon_uri";
|
||||
field public static final java.lang.String INSTALL_STATE = "install_state";
|
||||
field public static final java.lang.String INSTALL_TIME = "install_time";
|
||||
field public static final java.lang.String IS_DEFAULT_THEME = "is_default_theme";
|
||||
field public static final java.lang.String IS_LEGACY_ICONPACK = "is_legacy_iconpack";
|
||||
field public static final java.lang.String IS_LEGACY_THEME = "is_legacy_theme";
|
||||
field public static final java.lang.String LAST_UPDATE_TIME = "updateTime";
|
||||
field public static final java.lang.String LOCKSCREEN_URI = "lockscreen_uri";
|
||||
field public static final java.lang.String MODIFIES_ALARMS = "mods_alarms";
|
||||
field public static final java.lang.String MODIFIES_BOOT_ANIM = "mods_bootanim";
|
||||
field public static final java.lang.String MODIFIES_FONTS = "mods_fonts";
|
||||
field public static final java.lang.String MODIFIES_ICONS = "mods_icons";
|
||||
field public static final java.lang.String MODIFIES_LAUNCHER = "mods_homescreen";
|
||||
field public static final java.lang.String MODIFIES_LIVE_LOCK_SCREEN = "mods_live_lock_screen";
|
||||
field public static final java.lang.String MODIFIES_LOCKSCREEN = "mods_lockscreen";
|
||||
field public static final java.lang.String MODIFIES_NAVIGATION_BAR = "mods_navigation_bar";
|
||||
field public static final java.lang.String MODIFIES_NOTIFICATIONS = "mods_notifications";
|
||||
field public static final java.lang.String MODIFIES_OVERLAYS = "mods_overlays";
|
||||
field public static final java.lang.String MODIFIES_RINGTONES = "mods_ringtones";
|
||||
field public static final java.lang.String MODIFIES_STATUS_BAR = "mods_status_bar";
|
||||
field public static final java.lang.String OVERLAYS_URI = "overlays_uri";
|
||||
field public static final java.lang.String PKG_NAME = "pkg_name";
|
||||
field public static final java.lang.String PRESENT_AS_THEME = "present_as_theme";
|
||||
field public static final java.lang.String PRIMARY_COLOR = "primary_color";
|
||||
field public static final java.lang.String SECONDARY_COLOR = "secondary_color";
|
||||
field public static final java.lang.String STATUSBAR_URI = "status_uri";
|
||||
field public static final java.lang.String STYLE_URI = "style_uri";
|
||||
field public static final java.lang.String TARGET_API = "target_api";
|
||||
field public static final java.lang.String TITLE = "title";
|
||||
field public static final java.lang.String WALLPAPER_URI = "wallpaper_uri";
|
||||
field public static final java.lang.String _ID = "_id";
|
||||
}
|
||||
|
||||
public static class ThemesContract.ThemesColumns.InstallState {
|
||||
ctor public ThemesContract.ThemesColumns.InstallState();
|
||||
field public static final int INSTALLED = 3; // 0x3
|
||||
field public static final int INSTALLING = 1; // 0x1
|
||||
field public static final int UNKNOWN = 0; // 0x0
|
||||
field public static final int UPDATING = 2; // 0x2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package cyanogenmod.util {
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.platform.internal;
|
||||
|
||||
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 org.cyanogenmod.internal.util.ThemeUtils;
|
||||
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
import cyanogenmod.themes.IThemeService;
|
||||
import cyanogenmod.themes.ThemeChangeRequest;
|
||||
import cyanogenmod.themes.ThemeChangeRequest.RequestType;
|
||||
|
||||
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(R.string.theme_reset_notification_title);
|
||||
String body = context.getString(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);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.platform.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Binder;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import com.android.server.SystemService;
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
|
||||
import org.cyanogenmod.internal.themes.IIconCacheManager;
|
||||
import org.cyanogenmod.internal.util.ThemeUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
/** @hide */
|
||||
public class IconCacheManagerService extends SystemService {
|
||||
private static final String TAG = IconCacheManagerService.class.getSimpleName();
|
||||
|
||||
private static final long MAX_ICON_CACHE_SIZE = 33554432L; // 32MB
|
||||
private static final long PURGED_ICON_CACHE_SIZE = 25165824L; // 24 MB
|
||||
|
||||
private long mIconCacheSize = 0L;
|
||||
|
||||
public IconCacheManagerService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Log.d(TAG, "registerIconCache cmiconcache: " + this);
|
||||
publishBinderService(CMContextConstants.CM_ICON_CACHE_SERVICE, mService);
|
||||
}
|
||||
|
||||
private void purgeIconCache() {
|
||||
Log.d(TAG, "Purging icon cahe of size " + mIconCacheSize);
|
||||
File cacheDir = new File(ThemeUtils.SYSTEM_THEME_ICON_CACHE_DIR);
|
||||
File[] files = cacheDir.listFiles();
|
||||
Arrays.sort(files, mOldestFilesFirstComparator);
|
||||
for (File f : files) {
|
||||
if (!f.isDirectory()) {
|
||||
final long size = f.length();
|
||||
if(f.delete()) mIconCacheSize -= size;
|
||||
}
|
||||
if (mIconCacheSize <= PURGED_ICON_CACHE_SIZE) break;
|
||||
}
|
||||
}
|
||||
|
||||
private Comparator<File> mOldestFilesFirstComparator = new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(File lhs, File rhs) {
|
||||
return (int) (lhs.lastModified() - rhs.lastModified());
|
||||
}
|
||||
};
|
||||
|
||||
private IBinder mService = new IIconCacheManager.Stub() {
|
||||
@Override
|
||||
public boolean cacheComposedIcon(Bitmap icon, String fileName) throws RemoteException {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
boolean success;
|
||||
FileOutputStream os;
|
||||
final File cacheDir = new File(ThemeUtils.SYSTEM_THEME_ICON_CACHE_DIR);
|
||||
if (cacheDir.listFiles().length == 0) {
|
||||
mIconCacheSize = 0;
|
||||
}
|
||||
try {
|
||||
File outFile = new File(cacheDir, fileName);
|
||||
os = new FileOutputStream(outFile);
|
||||
icon.compress(Bitmap.CompressFormat.PNG, 90, os);
|
||||
os.close();
|
||||
FileUtils.setPermissions(outFile,
|
||||
FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH,
|
||||
-1, -1);
|
||||
mIconCacheSize += outFile.length();
|
||||
if (mIconCacheSize > MAX_ICON_CACHE_SIZE) {
|
||||
purgeIconCache();
|
||||
}
|
||||
success = true;
|
||||
} catch (Exception e) {
|
||||
success = false;
|
||||
Log.w(TAG, "Unable to cache icon " + fileName, e);
|
||||
}
|
||||
Binder.restoreCallingIdentity(token);
|
||||
return success;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -144,6 +144,27 @@
|
||||
android:description="@string/permdesc_thirdPartyKeyguard"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<!-- Allows an application to use ThemeManager -->
|
||||
<permission android:name="cyanogenmod.permission.ACCESS_THEME_MANAGER"
|
||||
android:label="@string/permlab_accessThemeService"
|
||||
android:description="@string/permdesc_accessThemeService"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<!-- Allows an application to read the current theme configuration and
|
||||
get information about the various themes currently installed -->
|
||||
<permission android:name="cyanogenmod.permission.READ_THEMES"
|
||||
android:label="@string/permlab_readThemes"
|
||||
android:description="@string/permdesc_readThemesDesc"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<!-- Allows an application to write the current theme configuration and
|
||||
write information about the various themes currently installed.
|
||||
Changing themes should be done through the service ACCESS_THEME_MANAGER -->
|
||||
<permission android:name="cyanogenmod.permission.WRITE_THEMES"
|
||||
android:label="@string/permlab_writeThemes"
|
||||
android:description="@string/permdesc_writeThemesDesc"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<application android:process="system"
|
||||
android:persistent="true"
|
||||
android:hasCode="false"
|
||||
|
@ -136,4 +136,29 @@
|
||||
<string name="touchscreen_gesture_extras">Extras</string>
|
||||
<string name="touchscreen_gesture_haptic_feedback">Haptic feedback</string>
|
||||
<string name="touchscreen_gesture_haptic_feedback_summary">Vibrate when a gesture got detected</string>
|
||||
|
||||
<!-- Theme installation error notification -->
|
||||
<string name="theme_install_error_title">Failed to install theme</string>
|
||||
<string name="theme_install_error_message"><xliff:g id="theme">%1$s</xliff:g> failed to install</string>
|
||||
|
||||
<!-- Theme reset notification -->
|
||||
<string name="theme_reset_notification_title">Theme reset</string>
|
||||
<string name="theme_reset_notification_message">System theme restored due to multiple app crashes.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_accessThemeService">access theme service</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_accessThemeService">Allows an app to access the theme service. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_readThemes">read your theme info</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_readThemesDesc">Allows the app to read your themes and
|
||||
determine which theme you have applied.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_writeThemes">modify your themes</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_writeThemesDesc">Allows the app to insert new themes and modify which theme you have applied.</string>
|
||||
|
||||
</resources>
|
||||
|
@ -93,4 +93,13 @@
|
||||
<java-symbol type="string" name="touchscreen_gesture_extras" />
|
||||
<java-symbol type="string" name="touchscreen_gesture_haptic_feedback" />
|
||||
<java-symbol type="string" name="touchscreen_gesture_haptic_feedback_summary" />
|
||||
|
||||
<!-- Theme install failure notification -->
|
||||
<java-symbol type="string" name="theme_install_error_title" />
|
||||
<java-symbol type="string" name="theme_install_error_message" />
|
||||
|
||||
<!-- Theme reset notification -->
|
||||
<java-symbol type="string" name="theme_reset_notification_title" />
|
||||
<java-symbol type="string" name="theme_reset_notification_message" />
|
||||
|
||||
</resources>
|
||||
|
@ -97,4 +97,18 @@ public final class CMContextConstants {
|
||||
* @hide
|
||||
*/
|
||||
public static final String CM_PERFORMANCE_SERVICE = "cmperformance";
|
||||
|
||||
/**
|
||||
* Controls changing and applying themes
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String CM_THEME_SERVICE = "cmthemes";
|
||||
|
||||
/**
|
||||
* Manages composed icons
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String CM_ICON_CACHE_SERVICE = "cmiconcache";
|
||||
}
|
||||
|
@ -88,4 +88,50 @@ public class Intent {
|
||||
public static final String ACTION_INITIALIZE_CM_HARDWARE =
|
||||
"cyanogenmod.intent.action.INITIALIZE_CM_HARDWARE";
|
||||
|
||||
/**
|
||||
* Broadcast Action: Indicate that an unrecoverable error happened during app launch.
|
||||
* Could indicate that curently applied theme is malicious.
|
||||
* @hide
|
||||
*/
|
||||
public static final String ACTION_APP_FAILURE = "cyanogenmod.intent.action.APP_FAILURE";
|
||||
|
||||
/**
|
||||
* Used to indicate that a theme package has been installed or un-installed.
|
||||
*/
|
||||
public static final String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE =
|
||||
"cyanogenmod.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE";
|
||||
|
||||
/**
|
||||
* Action sent from the provider when a theme has been fully installed. Fully installed
|
||||
* means that the apk was installed by PackageManager and the theme resources were
|
||||
* processed and cached by {@link org.cyanogenmod.platform.internal.ThemeManagerService}
|
||||
* Requires the {@link cyanogenmod.platform.Manifest.permission#READ_THEMES} permission to
|
||||
* receive this broadcast.
|
||||
*/
|
||||
public static final String ACTION_THEME_INSTALLED =
|
||||
"cyanogenmod.intent.action.THEME_INSTALLED";
|
||||
|
||||
/**
|
||||
* Action sent from the provider when a theme has been updated.
|
||||
* Requires the {@link cyanogenmod.platform.Manifest.permission#READ_THEMES} permission to
|
||||
* receive this broadcast.
|
||||
*/
|
||||
public static final String ACTION_THEME_UPDATED =
|
||||
"cyanogenmod.intent.action.THEME_UPDATED";
|
||||
|
||||
/**
|
||||
* Action sent from the provider when a theme has been removed.
|
||||
* Requires the {@link cyanogenmod.platform.Manifest.permission#READ_THEMES} permission to
|
||||
* receive this broadcast.
|
||||
*/
|
||||
public static final String ACTION_THEME_REMOVED =
|
||||
"cyanogenmod.intent.action.THEME_REMOVED";
|
||||
|
||||
/**
|
||||
* Uri scheme used to broadcast the theme's package name when broadcasting
|
||||
* {@link Intent#ACTION_THEME_INSTALLED} or
|
||||
* {@link Intent#ACTION_THEME_REMOVED}
|
||||
*/
|
||||
public static final String URI_SCHEME_PACKAGE = "package";
|
||||
|
||||
}
|
||||
|
717
src/java/cyanogenmod/providers/ThemesContract.java
Normal file
717
src/java/cyanogenmod/providers/ThemesContract.java
Normal file
@ -0,0 +1,717 @@
|
||||
/*
|
||||
* 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 cyanogenmod.providers;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The contract between the themes provider and applications. Contains
|
||||
* definitions for the supported URIs and columns.
|
||||
* </p>
|
||||
*/
|
||||
public class ThemesContract {
|
||||
/** The authority for the themes provider */
|
||||
public static final String AUTHORITY = "com.cyanogenmod.themes";
|
||||
/** A content:// style uri to the authority for the themes provider */
|
||||
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
|
||||
|
||||
public static class ThemesColumns {
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "themes");
|
||||
|
||||
/**
|
||||
* The unique ID for a row.
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
public static final String _ID = "_id";
|
||||
|
||||
/**
|
||||
* The user visible title.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String TITLE = "title";
|
||||
|
||||
/**
|
||||
* Unique text to identify the apk pkg. ie "com.foo.bar"
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String PKG_NAME = "pkg_name";
|
||||
|
||||
/**
|
||||
* A 32 bit RRGGBB color representative of the themes color scheme
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String PRIMARY_COLOR = "primary_color";
|
||||
|
||||
/**
|
||||
* A 2nd 32 bit RRGGBB color representative of the themes color scheme
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String SECONDARY_COLOR = "secondary_color";
|
||||
|
||||
/**
|
||||
* Name of the author of the theme
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String AUTHOR = "author";
|
||||
|
||||
/**
|
||||
* The time that this row was created on its originating client (msecs
|
||||
* since the epoch).
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String DATE_CREATED = "created";
|
||||
|
||||
/**
|
||||
* URI to an image that shows the homescreen with the theme applied
|
||||
* since the epoch).
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String HOMESCREEN_URI = "homescreen_uri";
|
||||
|
||||
/**
|
||||
* URI to an image that shows the lockscreen with theme applied
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String LOCKSCREEN_URI = "lockscreen_uri";
|
||||
|
||||
/**
|
||||
* URI to an image that shows the style (aka skin) with theme applied
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String STYLE_URI = "style_uri";
|
||||
|
||||
/**
|
||||
* TODO: Figure structure for actual animation instead of static
|
||||
* URI to an image of the boot_anim.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String BOOT_ANIM_URI = "bootanim_uri";
|
||||
|
||||
/**
|
||||
* URI to an image of the status bar for this theme.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String STATUSBAR_URI = "status_uri";
|
||||
|
||||
/**
|
||||
* URI to an image of the fonts in this theme.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String FONT_URI = "font_uri";
|
||||
|
||||
/**
|
||||
* URI to an image of the fonts in this theme.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String ICON_URI = "icon_uri";
|
||||
|
||||
/**
|
||||
* URI to an image of the fonts in this theme.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String OVERLAYS_URI = "overlays_uri";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies the launcher/homescreen else 0
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_LAUNCHER = "mods_homescreen";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies the lockscreen else 0
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_LOCKSCREEN = "mods_lockscreen";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies icons else 0
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_ICONS = "mods_icons";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies fonts
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_FONTS = "mods_fonts";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies boot animation
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_BOOT_ANIM = "mods_bootanim";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies notifications
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_NOTIFICATIONS = "mods_notifications";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies alarm sounds
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_ALARMS = "mods_alarms";
|
||||
|
||||
/**
|
||||
* 1 if theme modifies ringtones
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_RINGTONES = "mods_ringtones";
|
||||
|
||||
/**
|
||||
* 1 if theme has overlays
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_OVERLAYS = "mods_overlays";
|
||||
|
||||
/**
|
||||
* 1 if theme has an overlay for SystemUI/StatusBar
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_STATUS_BAR = "mods_status_bar";
|
||||
|
||||
/**
|
||||
* 1 if theme has an overlay for SystemUI/NavBar
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_NAVIGATION_BAR = "mods_navigation_bar";
|
||||
|
||||
/**
|
||||
* 1 if theme has a live lock screen
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String MODIFIES_LIVE_LOCK_SCREEN = "mods_live_lock_screen";
|
||||
|
||||
/**
|
||||
* URI to the theme's wallpaper. We should support multiple wallpaper
|
||||
* but for now we will just have 1.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String WALLPAPER_URI = "wallpaper_uri";
|
||||
|
||||
/**
|
||||
* 1 if this row should actually be presented as a theme to the user.
|
||||
* For example if a "theme" only modifies one component (ex icons) then
|
||||
* we do not present it to the user under the themes table.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String PRESENT_AS_THEME = "present_as_theme";
|
||||
|
||||
/**
|
||||
* 1 if this theme is a legacy theme.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String IS_LEGACY_THEME = "is_legacy_theme";
|
||||
|
||||
/**
|
||||
* 1 if this theme is the system default theme.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String IS_DEFAULT_THEME = "is_default_theme";
|
||||
|
||||
/**
|
||||
* 1 if this theme is a legacy iconpack. A legacy icon pack is an APK that was written
|
||||
* for Trebuchet or a 3rd party launcher.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String IS_LEGACY_ICONPACK = "is_legacy_iconpack";
|
||||
|
||||
/**
|
||||
* install/update time in millisecs. When the row is inserted this column
|
||||
* is populated by the PackageInfo. It is used for syncing to PM
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String LAST_UPDATE_TIME = "updateTime";
|
||||
|
||||
/**
|
||||
* install time in millisecs. When the row is inserted this column
|
||||
* is populated by the PackageInfo.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String INSTALL_TIME = "install_time";
|
||||
|
||||
/**
|
||||
* The target API this theme supports
|
||||
* is populated by the PackageInfo.
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String TARGET_API = "target_api";
|
||||
|
||||
/**
|
||||
* The install state of the theme.
|
||||
* Can be one of the following:
|
||||
* {@link InstallState#UNKNOWN}
|
||||
* {@link InstallState#INSTALLING}
|
||||
* {@link InstallState#UPDATING}
|
||||
* {@link InstallState#INSTALLED}
|
||||
* <P>Type: INTEGER</P>
|
||||
* <P>Default: 0</P>
|
||||
*/
|
||||
public static final String INSTALL_STATE = "install_state";
|
||||
|
||||
public static class InstallState {
|
||||
public static final int UNKNOWN = 0;
|
||||
public static final int INSTALLING = 1;
|
||||
public static final int UPDATING = 2;
|
||||
public static final int INSTALLED = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key-value table which assigns a component (ex wallpaper) to a theme's package
|
||||
*/
|
||||
public static class MixnMatchColumns {
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "mixnmatch");
|
||||
|
||||
/**
|
||||
* The unique key for a row. See the KEY_* constants
|
||||
* for valid examples
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String COL_KEY = "key";
|
||||
|
||||
/**
|
||||
* The package name that corresponds to a given component.
|
||||
* <P>Type: String</P>
|
||||
*/
|
||||
public static final String COL_VALUE = "value";
|
||||
|
||||
/**
|
||||
* The package name that corresponds to where this component was applied from previously
|
||||
* <P>Type: String</P>
|
||||
*/
|
||||
public static final String COL_PREV_VALUE = "previous_value";
|
||||
|
||||
/**
|
||||
* Time when this entry was last updated
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
public static final String COL_UPDATE_TIME = "update_time";
|
||||
|
||||
/*
|
||||
* The unique ID for the component within a theme.
|
||||
* Always 0 unless multiples of a component exist.
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
public static final String COL_COMPONENT_ID = "component_id";
|
||||
|
||||
/**
|
||||
* Valid keys
|
||||
*/
|
||||
public static final String KEY_HOMESCREEN = "mixnmatch_homescreen";
|
||||
public static final String KEY_LOCKSCREEN = "mixnmatch_lockscreen";
|
||||
public static final String KEY_ICONS = "mixnmatch_icons";
|
||||
public static final String KEY_STATUS_BAR = "mixnmatch_status_bar";
|
||||
public static final String KEY_BOOT_ANIM = "mixnmatch_boot_anim";
|
||||
public static final String KEY_FONT = "mixnmatch_font";
|
||||
public static final String KEY_ALARM = "mixnmatch_alarm";
|
||||
public static final String KEY_NOTIFICATIONS = "mixnmatch_notifications";
|
||||
public static final String KEY_RINGTONE = "mixnmatch_ringtone";
|
||||
public static final String KEY_OVERLAYS = "mixnmatch_overlays";
|
||||
public static final String KEY_NAVIGATION_BAR = "mixnmatch_navigation_bar";
|
||||
public static final String KEY_LIVE_LOCK_SCREEN = "mixnmatch_live_lock_screen";
|
||||
|
||||
public static final String[] ROWS = { KEY_HOMESCREEN,
|
||||
KEY_LOCKSCREEN,
|
||||
KEY_ICONS,
|
||||
KEY_STATUS_BAR,
|
||||
KEY_BOOT_ANIM,
|
||||
KEY_FONT,
|
||||
KEY_NOTIFICATIONS,
|
||||
KEY_RINGTONE,
|
||||
KEY_ALARM,
|
||||
KEY_OVERLAYS,
|
||||
KEY_NAVIGATION_BAR,
|
||||
KEY_LIVE_LOCK_SCREEN
|
||||
};
|
||||
|
||||
/**
|
||||
* For a given key value in the MixNMatch table, return the column
|
||||
* associated with it in the Themes Table. This is useful for URI based
|
||||
* elements like wallpaper where the caller wishes to determine the
|
||||
* wallpaper URI.
|
||||
*/
|
||||
public static String componentToImageColName(String component) {
|
||||
if (component.equals(MixnMatchColumns.KEY_HOMESCREEN)) {
|
||||
return ThemesColumns.HOMESCREEN_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_LOCKSCREEN)) {
|
||||
return ThemesColumns.LOCKSCREEN_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_BOOT_ANIM)) {
|
||||
return ThemesColumns.BOOT_ANIM_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_FONT)) {
|
||||
return ThemesColumns.FONT_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_ICONS)) {
|
||||
return ThemesColumns.ICON_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
|
||||
return ThemesColumns.STATUSBAR_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_NOTIFICATIONS)) {
|
||||
throw new IllegalArgumentException("Notifications mixnmatch component does not have a related column");
|
||||
} else if (component.equals(MixnMatchColumns.KEY_RINGTONE)) {
|
||||
throw new IllegalArgumentException("Ringtone mixnmatch component does not have a related column");
|
||||
} else if (component.equals(MixnMatchColumns.KEY_OVERLAYS)) {
|
||||
return ThemesColumns.OVERLAYS_URI;
|
||||
} else if (component.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Status bar mixnmatch component does not have a related column");
|
||||
} else if (component.equals(MixnMatchColumns.KEY_NAVIGATION_BAR)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Navigation bar mixnmatch component does not have a related column");
|
||||
} else if (component.equals(MixnMatchColumns.KEY_LIVE_LOCK_SCREEN)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Live lock screen mixnmatch component does not have a related column");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A component in the themes table (IE "mods_wallpaper") has an
|
||||
* equivalent key in mixnmatch table
|
||||
*/
|
||||
public static String componentToMixNMatchKey(String component) {
|
||||
if (component.equals(ThemesColumns.MODIFIES_LAUNCHER)) {
|
||||
return MixnMatchColumns.KEY_HOMESCREEN;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_ICONS)) {
|
||||
return MixnMatchColumns.KEY_ICONS;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_LOCKSCREEN)) {
|
||||
return MixnMatchColumns.KEY_LOCKSCREEN;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_FONTS)) {
|
||||
return MixnMatchColumns.KEY_FONT;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_BOOT_ANIM)) {
|
||||
return MixnMatchColumns.KEY_BOOT_ANIM;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_ALARMS)) {
|
||||
return MixnMatchColumns.KEY_ALARM;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_NOTIFICATIONS)) {
|
||||
return MixnMatchColumns.KEY_NOTIFICATIONS;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_RINGTONES)) {
|
||||
return MixnMatchColumns.KEY_RINGTONE;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_OVERLAYS)) {
|
||||
return MixnMatchColumns.KEY_OVERLAYS;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_STATUS_BAR)) {
|
||||
return MixnMatchColumns.KEY_STATUS_BAR;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_NAVIGATION_BAR)) {
|
||||
return MixnMatchColumns.KEY_NAVIGATION_BAR;
|
||||
} else if (component.equals(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN)) {
|
||||
return MixnMatchColumns.KEY_LIVE_LOCK_SCREEN;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mixnmatch key in has an
|
||||
* equivalent value in the themes table
|
||||
*/
|
||||
public static String mixNMatchKeyToComponent(String mixnmatchKey) {
|
||||
if (mixnmatchKey.equals(MixnMatchColumns.KEY_HOMESCREEN)) {
|
||||
return ThemesColumns.MODIFIES_LAUNCHER;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_ICONS)) {
|
||||
return ThemesColumns.MODIFIES_ICONS;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_LOCKSCREEN)) {
|
||||
return ThemesColumns.MODIFIES_LOCKSCREEN;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_FONT)) {
|
||||
return ThemesColumns.MODIFIES_FONTS;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_BOOT_ANIM)) {
|
||||
return ThemesColumns.MODIFIES_BOOT_ANIM;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_ALARM)) {
|
||||
return ThemesColumns.MODIFIES_ALARMS;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_NOTIFICATIONS)) {
|
||||
return ThemesColumns.MODIFIES_NOTIFICATIONS;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_RINGTONE)) {
|
||||
return ThemesColumns.MODIFIES_RINGTONES;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_OVERLAYS)) {
|
||||
return ThemesColumns.MODIFIES_OVERLAYS;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_STATUS_BAR)) {
|
||||
return ThemesColumns.MODIFIES_STATUS_BAR;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_NAVIGATION_BAR)) {
|
||||
return ThemesColumns.MODIFIES_NAVIGATION_BAR;
|
||||
} else if (mixnmatchKey.equals(MixnMatchColumns.KEY_LIVE_LOCK_SCREEN)) {
|
||||
return ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Table containing cached preview files for a given theme
|
||||
*/
|
||||
public static class PreviewColumns {
|
||||
/**
|
||||
* Uri for retrieving the previews table.
|
||||
* Querying the themes provider using this URI will return a cursor with a key and value
|
||||
* columns, and a row for each component.
|
||||
*/
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "previews");
|
||||
|
||||
/**
|
||||
* Uri for retrieving the previews for the currently applied components.
|
||||
* Querying the themes provider using this URI will return a cursor with a single row
|
||||
* containing all the previews for the components that are currently applied.
|
||||
*/
|
||||
public static final Uri APPLIED_URI = Uri.withAppendedPath(AUTHORITY_URI,
|
||||
"applied_previews");
|
||||
|
||||
/**
|
||||
* Uri for retrieving the default previews for the theme.
|
||||
* Querying the themes provider using this URI will return a cursor with a single row
|
||||
* containing all the previews for the default components of the current theme.
|
||||
*/
|
||||
public static final Uri COMPONENTS_URI = Uri.withAppendedPath(AUTHORITY_URI,
|
||||
"components_previews");
|
||||
|
||||
/**
|
||||
* The unique ID for a row.
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
public static final String _ID = "_id";
|
||||
|
||||
/**
|
||||
* The unique ID for the theme these previews belong to.
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
public static final String THEME_ID = "theme_id";
|
||||
|
||||
/**
|
||||
* The unique ID for the component within a theme.
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
public static final String COMPONENT_ID = "component_id";
|
||||
|
||||
/**
|
||||
* The unique key for a row. See the Valid key constants section below
|
||||
* for valid examples
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String COL_KEY = "key";
|
||||
|
||||
/**
|
||||
* The package name that corresponds to a given component.
|
||||
* <P>Type: String</P>
|
||||
*/
|
||||
public static final String COL_VALUE = "value";
|
||||
|
||||
/**
|
||||
* Valid keys
|
||||
*/
|
||||
|
||||
/**
|
||||
* Cached image of the themed status bar background.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_BACKGROUND = "statusbar_background";
|
||||
|
||||
/**
|
||||
* Cached image of the themed bluetooth status icon.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_BLUETOOTH_ICON = "statusbar_bluetooth_icon";
|
||||
|
||||
/**
|
||||
* Cached image of the themed wifi status icon.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_WIFI_ICON = "statusbar_wifi_icon";
|
||||
|
||||
/**
|
||||
* Cached image of the themed cellular signal status icon.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_SIGNAL_ICON = "statusbar_signal_icon";
|
||||
|
||||
/**
|
||||
* Cached image of the themed battery using portrait style.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_BATTERY_PORTRAIT = "statusbar_battery_portrait";
|
||||
|
||||
/**
|
||||
* Cached image of the themed battery using landscape style.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_BATTERY_LANDSCAPE = "statusbar_battery_landscape";
|
||||
|
||||
/**
|
||||
* Cached image of the themed battery using circle style.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_BATTERY_CIRCLE = "statusbar_battery_circle";
|
||||
|
||||
/**
|
||||
* The themed color used for clock text in the status bar.
|
||||
* <P>Type: INTEGER (int)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_CLOCK_TEXT_COLOR = "statusbar_clock_text_color";
|
||||
|
||||
/**
|
||||
* The themed margin value between the wifi and rssi signal icons.
|
||||
* <P>Type: INTEGER (int)</P>
|
||||
*/
|
||||
public static final String STATUSBAR_WIFI_COMBO_MARGIN_END = "wifi_combo_margin_end";
|
||||
|
||||
/**
|
||||
* Cached image of the themed navigation bar background.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String NAVBAR_BACKGROUND = "navbar_background";
|
||||
|
||||
/**
|
||||
* Cached image of the themed back button.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String NAVBAR_BACK_BUTTON = "navbar_back_button";
|
||||
|
||||
/**
|
||||
* Cached image of the themed home button.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String NAVBAR_HOME_BUTTON = "navbar_home_button";
|
||||
|
||||
/**
|
||||
* Cached image of the themed recents button.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String NAVBAR_RECENT_BUTTON = "navbar_recent_button";
|
||||
|
||||
/**
|
||||
* Cached image of the 1/3 icons
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String ICON_PREVIEW_1 = "icon_preview_1";
|
||||
|
||||
/**
|
||||
* Cached image of the 2/3 icons
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String ICON_PREVIEW_2 = "icon_preview_2";
|
||||
|
||||
/**
|
||||
* Cached image of the 3/3 icons
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String ICON_PREVIEW_3 = "icon_preview_3";
|
||||
|
||||
/**
|
||||
* Full path to the theme's wallpaper asset.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String WALLPAPER_FULL = "wallpaper_full";
|
||||
|
||||
/**
|
||||
* Cached preview of the theme's wallpaper which is larger than the thumbnail
|
||||
* but smaller than the full sized wallpaper.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String WALLPAPER_PREVIEW = "wallpaper_preview";
|
||||
|
||||
/**
|
||||
* Cached thumbnail of the theme's wallpaper
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String WALLPAPER_THUMBNAIL = "wallpaper_thumbnail";
|
||||
|
||||
/**
|
||||
* Cached preview of the theme's lockscreen wallpaper which is larger than the thumbnail
|
||||
* but smaller than the full sized lockscreen wallpaper.
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String LOCK_WALLPAPER_PREVIEW = "lock_wallpaper_preview";
|
||||
|
||||
/**
|
||||
* Cached thumbnail of the theme's lockscreen wallpaper
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String LOCK_WALLPAPER_THUMBNAIL = "lock_wallpaper_thumbnail";
|
||||
|
||||
/**
|
||||
* Cached preview of UI controls representing the theme's style
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STYLE_PREVIEW = "style_preview";
|
||||
|
||||
/**
|
||||
* Cached thumbnail preview of UI controls representing the theme's style
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String STYLE_THUMBNAIL = "style_thumbnail";
|
||||
|
||||
/**
|
||||
* Cached thumbnail of the theme's boot animation
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String BOOTANIMATION_THUMBNAIL = "bootanimation_thumbnail";
|
||||
|
||||
/**
|
||||
* Cached preview of live lock screen
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String LIVE_LOCK_SCREEN_PREVIEW = "live_lock_screen_preview";
|
||||
|
||||
/**
|
||||
* Cached thumbnail preview of live lock screen
|
||||
* <P>Type: String (file path)</P>
|
||||
*/
|
||||
public static final String LIVE_LOCK_SCREEN_THUMBNAIL = "live_lock_screen_thumbnail";
|
||||
|
||||
public static final String[] VALID_KEYS = {
|
||||
STATUSBAR_BACKGROUND,
|
||||
STATUSBAR_BLUETOOTH_ICON,
|
||||
STATUSBAR_WIFI_ICON,
|
||||
STATUSBAR_SIGNAL_ICON,
|
||||
STATUSBAR_BATTERY_PORTRAIT,
|
||||
STATUSBAR_BATTERY_LANDSCAPE,
|
||||
STATUSBAR_BATTERY_CIRCLE,
|
||||
STATUSBAR_CLOCK_TEXT_COLOR,
|
||||
STATUSBAR_WIFI_COMBO_MARGIN_END,
|
||||
NAVBAR_BACKGROUND,
|
||||
NAVBAR_BACK_BUTTON,
|
||||
NAVBAR_HOME_BUTTON,
|
||||
NAVBAR_RECENT_BUTTON,
|
||||
ICON_PREVIEW_1,
|
||||
ICON_PREVIEW_2,
|
||||
ICON_PREVIEW_3,
|
||||
WALLPAPER_FULL,
|
||||
WALLPAPER_PREVIEW,
|
||||
WALLPAPER_THUMBNAIL,
|
||||
LOCK_WALLPAPER_PREVIEW,
|
||||
LOCK_WALLPAPER_THUMBNAIL,
|
||||
STYLE_PREVIEW,
|
||||
STYLE_THUMBNAIL,
|
||||
BOOTANIMATION_THUMBNAIL,
|
||||
LIVE_LOCK_SCREEN_PREVIEW,
|
||||
LIVE_LOCK_SCREEN_THUMBNAIL,
|
||||
};
|
||||
}
|
||||
}
|
23
src/java/cyanogenmod/themes/IThemeChangeListener.aidl
Normal file
23
src/java/cyanogenmod/themes/IThemeChangeListener.aidl
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2014-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 cyanogenmod.themes;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IThemeChangeListener {
|
||||
void onProgress(int progress);
|
||||
void onFinish(boolean isSuccess);
|
||||
}
|
22
src/java/cyanogenmod/themes/IThemeProcessingListener.aidl
Normal file
22
src/java/cyanogenmod/themes/IThemeProcessingListener.aidl
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2014-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 cyanogenmod.themes;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IThemeProcessingListener {
|
||||
void onFinishedProcessing(String pkgName);
|
||||
}
|
44
src/java/cyanogenmod/themes/IThemeService.aidl
Normal file
44
src/java/cyanogenmod/themes/IThemeService.aidl
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2014-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 cyanogenmod.themes;
|
||||
|
||||
import cyanogenmod.themes.IThemeChangeListener;
|
||||
import cyanogenmod.themes.IThemeProcessingListener;
|
||||
import cyanogenmod.themes.ThemeChangeRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** {@hide} */
|
||||
interface IThemeService {
|
||||
oneway void requestThemeChangeUpdates(in IThemeChangeListener listener);
|
||||
oneway void removeUpdates(in IThemeChangeListener listener);
|
||||
|
||||
oneway void requestThemeChange(in ThemeChangeRequest request, boolean removePerAppThemes);
|
||||
oneway void applyDefaultTheme();
|
||||
boolean isThemeApplying();
|
||||
int getProgress();
|
||||
|
||||
boolean processThemeResources(String themePkgName);
|
||||
boolean isThemeBeingProcessed(String themePkgName);
|
||||
oneway void registerThemeProcessingListener(in IThemeProcessingListener listener);
|
||||
oneway void unregisterThemeProcessingListener(in IThemeProcessingListener listener);
|
||||
|
||||
oneway void rebuildResourceCache();
|
||||
|
||||
long getLastThemeChangeTime();
|
||||
int getLastThemeChangeRequestType();
|
||||
}
|
19
src/java/cyanogenmod/themes/ThemeChangeRequest.aidl
Normal file
19
src/java/cyanogenmod/themes/ThemeChangeRequest.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 cyanogenmod.themes;
|
||||
|
||||
parcelable ThemeChangeRequest;
|
329
src/java/cyanogenmod/themes/ThemeChangeRequest.java
Normal file
329
src/java/cyanogenmod/themes/ThemeChangeRequest.java
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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 cyanogenmod.themes;
|
||||
|
||||
import android.content.pm.ThemeUtils;
|
||||
import android.content.res.ThemeConfig;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import cyanogenmod.os.Build;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static cyanogenmod.providers.ThemesContract.ThemesColumns.*;
|
||||
|
||||
public final class ThemeChangeRequest implements Parcelable {
|
||||
public static final int DEFAULT_WALLPAPER_ID = -1;
|
||||
|
||||
private final Map<String, String> mThemeComponents = new HashMap<>();
|
||||
private final Map<String, String> mPerAppOverlays = new HashMap<>();
|
||||
private RequestType mRequestType;
|
||||
private long mWallpaperId = -1;
|
||||
|
||||
public String getOverlayThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_OVERLAYS);
|
||||
}
|
||||
|
||||
public String getStatusBarThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_STATUS_BAR);
|
||||
}
|
||||
|
||||
public String getNavBarThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_NAVIGATION_BAR);
|
||||
}
|
||||
|
||||
public String getFontThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_FONTS);
|
||||
}
|
||||
|
||||
public String getIconsThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_ICONS);
|
||||
}
|
||||
|
||||
public String getBootanimationThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_BOOT_ANIM);
|
||||
}
|
||||
|
||||
public String getWallpaperThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_LAUNCHER);
|
||||
}
|
||||
|
||||
public String getLockWallpaperThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_LOCKSCREEN);
|
||||
}
|
||||
|
||||
public String getAlarmThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_ALARMS);
|
||||
}
|
||||
|
||||
public String getNotificationThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
public String getRingtoneThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_RINGTONES);
|
||||
}
|
||||
|
||||
public String getLiveLockScreenThemePackageName() {
|
||||
return getThemePackageNameForComponent(MODIFIES_LIVE_LOCK_SCREEN);
|
||||
}
|
||||
|
||||
public final Map<String, String> getThemeComponentsMap() {
|
||||
return Collections.unmodifiableMap(mThemeComponents);
|
||||
}
|
||||
|
||||
public long getWallpaperId() {
|
||||
return mWallpaperId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapping for per app themes
|
||||
* @return A mapping of apps and the theme to apply for each one. or null if none set.
|
||||
*/
|
||||
public final Map<String, String> getPerAppOverlays() {
|
||||
return Collections.unmodifiableMap(mPerAppOverlays);
|
||||
}
|
||||
|
||||
public int getNumChangesRequested() {
|
||||
return mThemeComponents.size() + mPerAppOverlays.size();
|
||||
}
|
||||
|
||||
public RequestType getReqeustType() {
|
||||
return mRequestType;
|
||||
}
|
||||
|
||||
private String getThemePackageNameForComponent(String componentName) {
|
||||
return mThemeComponents.get(componentName);
|
||||
}
|
||||
|
||||
private ThemeChangeRequest(Map<String, String> components, Map<String, String> perAppThemes,
|
||||
RequestType requestType, long wallpaperId) {
|
||||
if (components != null) {
|
||||
mThemeComponents.putAll(components);
|
||||
}
|
||||
if (perAppThemes != null) {
|
||||
mPerAppOverlays.putAll(perAppThemes);
|
||||
}
|
||||
mRequestType = requestType;
|
||||
mWallpaperId = wallpaperId;
|
||||
}
|
||||
|
||||
private ThemeChangeRequest(Parcel source) {
|
||||
// Read parcelable version, make sure to define explicit changes
|
||||
// within {@link Build.PARCELABLE_VERSION);
|
||||
int version = source.readInt();
|
||||
int size = source.readInt();
|
||||
int start = source.dataPosition();
|
||||
|
||||
int numComponents = source.readInt();
|
||||
for (int i = 0; i < numComponents; i++) {
|
||||
mThemeComponents.put(source.readString(), source.readString());
|
||||
}
|
||||
|
||||
numComponents = source.readInt();
|
||||
for (int i = 0 ; i < numComponents; i++) {
|
||||
mPerAppOverlays.put(source.readString(), source.readString());
|
||||
}
|
||||
mRequestType = RequestType.values()[source.readInt()];
|
||||
mWallpaperId = source.readLong();
|
||||
source.setDataPosition(start + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Write parcelable version, make sure to define explicit changes
|
||||
// within {@link Build.PARCELABLE_VERSION);
|
||||
dest.writeInt(Build.PARCELABLE_VERSION);
|
||||
int sizePos = dest.dataPosition();
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
dest.writeInt(0);
|
||||
int dataStartPos = dest.dataPosition();
|
||||
|
||||
dest.writeInt(mThemeComponents.size());
|
||||
for (String component : mThemeComponents.keySet()) {
|
||||
dest.writeString(component);
|
||||
dest.writeString(mThemeComponents.get(component));
|
||||
}
|
||||
dest.writeInt((mPerAppOverlays.size()));
|
||||
for (String appPkgName : mPerAppOverlays.keySet()) {
|
||||
dest.writeString(appPkgName);
|
||||
dest.writeString(mPerAppOverlays.get(appPkgName));
|
||||
}
|
||||
dest.writeInt(mRequestType.ordinal());
|
||||
dest.writeLong(mWallpaperId);
|
||||
|
||||
// Go back and write size
|
||||
int size = dest.dataPosition() - dataStartPos;
|
||||
dest.setDataPosition(sizePos);
|
||||
dest.writeInt(size);
|
||||
dest.setDataPosition(dataStartPos + size);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ThemeChangeRequest> CREATOR =
|
||||
new Parcelable.Creator<ThemeChangeRequest>() {
|
||||
@Override
|
||||
public ThemeChangeRequest createFromParcel(Parcel source) {
|
||||
return new ThemeChangeRequest(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThemeChangeRequest[] newArray(int size) {
|
||||
return new ThemeChangeRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
public enum RequestType {
|
||||
USER_REQUEST,
|
||||
USER_REQUEST_MIXNMATCH,
|
||||
THEME_UPDATED,
|
||||
THEME_REMOVED,
|
||||
THEME_RESET
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
Map<String, String> mThemeComponents = new HashMap<>();
|
||||
Map<String, String> mPerAppOverlays = new HashMap<>();
|
||||
RequestType mRequestType = RequestType.USER_REQUEST;
|
||||
long mWallpaperId;
|
||||
|
||||
public Builder() {}
|
||||
|
||||
public Builder(ThemeConfig themeConfig) {
|
||||
if (themeConfig != null) {
|
||||
buildChangeRequestFromThemeConfig(themeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder setOverlay(String pkgName) {
|
||||
return setComponent(MODIFIES_OVERLAYS, pkgName);
|
||||
}
|
||||
|
||||
public Builder setStatusBar(String pkgName) {
|
||||
return setComponent(MODIFIES_STATUS_BAR, pkgName);
|
||||
}
|
||||
|
||||
public Builder setNavBar(String pkgName) {
|
||||
return setComponent(MODIFIES_NAVIGATION_BAR, pkgName);
|
||||
}
|
||||
|
||||
public Builder setFont(String pkgName) {
|
||||
return setComponent(MODIFIES_FONTS, pkgName);
|
||||
}
|
||||
|
||||
public Builder setIcons(String pkgName) {
|
||||
return setComponent(MODIFIES_ICONS, pkgName);
|
||||
}
|
||||
|
||||
public Builder setBootanimation(String pkgName) {
|
||||
return setComponent(MODIFIES_BOOT_ANIM, pkgName);
|
||||
}
|
||||
|
||||
public Builder setWallpaper(String pkgName) {
|
||||
return setComponent(MODIFIES_LAUNCHER, pkgName);
|
||||
}
|
||||
|
||||
// Used in the case that more than one wallpaper exists for a given pkg name
|
||||
public Builder setWallpaperId(long id) {
|
||||
mWallpaperId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setLockWallpaper(String pkgName) {
|
||||
return setComponent(MODIFIES_LOCKSCREEN, pkgName);
|
||||
}
|
||||
|
||||
public Builder setAlarm(String pkgName) {
|
||||
return setComponent(MODIFIES_ALARMS, pkgName);
|
||||
}
|
||||
|
||||
public Builder setNotification(String pkgName) {
|
||||
return setComponent(MODIFIES_NOTIFICATIONS, pkgName);
|
||||
}
|
||||
|
||||
public Builder setRingtone(String pkgName) {
|
||||
return setComponent(MODIFIES_RINGTONES, pkgName);
|
||||
}
|
||||
|
||||
public Builder setLiveLockScreen(String pkgName) {
|
||||
return setComponent(MODIFIES_LIVE_LOCK_SCREEN, pkgName);
|
||||
}
|
||||
|
||||
public Builder setComponent(String component, String pkgName) {
|
||||
if (pkgName != null) {
|
||||
mThemeComponents.put(component, pkgName);
|
||||
} else {
|
||||
mThemeComponents.remove(component);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAppOverlay(String appPkgName, String themePkgName) {
|
||||
if (appPkgName != null) {
|
||||
if (themePkgName != null) {
|
||||
mPerAppOverlays.put(appPkgName, themePkgName);
|
||||
} else {
|
||||
mPerAppOverlays.remove(appPkgName);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRequestType(RequestType requestType) {
|
||||
mRequestType = requestType != null ? requestType : RequestType.USER_REQUEST;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThemeChangeRequest build() {
|
||||
return new ThemeChangeRequest(mThemeComponents, mPerAppOverlays,
|
||||
mRequestType, mWallpaperId);
|
||||
}
|
||||
|
||||
private void buildChangeRequestFromThemeConfig(ThemeConfig themeConfig) {
|
||||
if (themeConfig.getFontPkgName() != null) {
|
||||
this.setFont(themeConfig.getFontPkgName());
|
||||
}
|
||||
if (themeConfig.getIconPackPkgName() != null) {
|
||||
this.setIcons(themeConfig.getIconPackPkgName());
|
||||
}
|
||||
if (themeConfig.getOverlayPkgName() != null) {
|
||||
this.setOverlay(themeConfig.getOverlayPkgName());
|
||||
}
|
||||
if (themeConfig.getOverlayForStatusBar() != null) {
|
||||
this.setStatusBar(themeConfig.getOverlayForStatusBar());
|
||||
}
|
||||
if (themeConfig.getOverlayForNavBar() != null) {
|
||||
this.setNavBar(themeConfig.getOverlayForNavBar());
|
||||
}
|
||||
|
||||
// Check if there are any per-app overlays using this theme
|
||||
final Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes();
|
||||
for (String appPkgName : themes.keySet()) {
|
||||
if (ThemeUtils.isPerAppThemeComponent(appPkgName)) {
|
||||
this.setAppOverlay(appPkgName, themes.get(appPkgName).getOverlayPkgName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
383
src/java/cyanogenmod/themes/ThemeManager.java
Normal file
383
src/java/cyanogenmod/themes/ThemeManager.java
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2014-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 cyanogenmod.themes;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
import cyanogenmod.themes.ThemeChangeRequest.RequestType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manages changing and applying of themes.
|
||||
* <p>Get an instance of this class by calling blah blah blah</p>
|
||||
*/
|
||||
public class ThemeManager {
|
||||
private static final String TAG = ThemeManager.class.getName();
|
||||
private static IThemeService sService;
|
||||
private static ThemeManager sInstance;
|
||||
private static Handler mHandler;
|
||||
|
||||
private Set<ThemeChangeListener> mChangeListeners = new ArraySet<>();
|
||||
|
||||
private Set<ThemeProcessingListener> mProcessingListeners = new ArraySet<>();
|
||||
|
||||
private ThemeManager() {
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
sService = getService();
|
||||
}
|
||||
|
||||
public static ThemeManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new ThemeManager();
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private static IThemeService getService() {
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
}
|
||||
IBinder b = ServiceManager.getService(CMContextConstants.CM_THEME_SERVICE);
|
||||
if (b != null) {
|
||||
sService = IThemeService.Stub.asInterface(b);
|
||||
return sService;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final IThemeChangeListener mThemeChangeListener = new IThemeChangeListener.Stub() {
|
||||
@Override
|
||||
public void onProgress(final int progress) throws RemoteException {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mChangeListeners) {
|
||||
List<ThemeChangeListener> listenersToRemove = new ArrayList<>();
|
||||
for (ThemeChangeListener listener : mChangeListeners) {
|
||||
try {
|
||||
listener.onProgress(progress);
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "Unable to update theme change progress", e);
|
||||
listenersToRemove.add(listener);
|
||||
}
|
||||
}
|
||||
if (listenersToRemove.size() > 0) {
|
||||
for (ThemeChangeListener listener : listenersToRemove) {
|
||||
mChangeListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(final boolean isSuccess) throws RemoteException {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mChangeListeners) {
|
||||
List<ThemeChangeListener> listenersToRemove = new ArrayList<>();
|
||||
for (ThemeChangeListener listener : mChangeListeners) {
|
||||
try {
|
||||
listener.onFinish(isSuccess);
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "Unable to update theme change listener", e);
|
||||
listenersToRemove.add(listener);
|
||||
}
|
||||
}
|
||||
if (listenersToRemove.size() > 0) {
|
||||
for (ThemeChangeListener listener : listenersToRemove) {
|
||||
mChangeListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private final IThemeProcessingListener mThemeProcessingListener =
|
||||
new IThemeProcessingListener.Stub() {
|
||||
@Override
|
||||
public void onFinishedProcessing(final String pkgName) throws RemoteException {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mProcessingListeners) {
|
||||
List<ThemeProcessingListener> listenersToRemove = new ArrayList<>();
|
||||
for (ThemeProcessingListener listener : mProcessingListeners) {
|
||||
try {
|
||||
listener.onFinishedProcessing(pkgName);
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "Unable to update theme change progress", e);
|
||||
listenersToRemove.add(listener);
|
||||
}
|
||||
}
|
||||
if (listenersToRemove.size() > 0) {
|
||||
for (ThemeProcessingListener listener : listenersToRemove) {
|
||||
mProcessingListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ThemeManager#registerThemeChangeListener(ThemeChangeListener)} instead
|
||||
*/
|
||||
public void addClient(ThemeChangeListener listener) {
|
||||
registerThemeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
|
||||
* instead
|
||||
*/
|
||||
public void removeClient(ThemeChangeListener listener) {
|
||||
unregisterThemeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
|
||||
* instead
|
||||
*/
|
||||
public void onClientPaused(ThemeChangeListener listener) {
|
||||
unregisterThemeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ThemeManager#registerThemeChangeListener(ThemeChangeListener)} instead
|
||||
*/
|
||||
public void onClientResumed(ThemeChangeListener listener) {
|
||||
registerThemeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
|
||||
* instead
|
||||
*/
|
||||
public void onClientDestroyed(ThemeChangeListener listener) {
|
||||
unregisterThemeChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link ThemeChangeListener} to be notified when a theme is done being processed.
|
||||
* @param listener {@link ThemeChangeListener} to register
|
||||
*/
|
||||
public void registerThemeChangeListener(ThemeChangeListener listener) {
|
||||
synchronized (mChangeListeners) {
|
||||
if (mChangeListeners.contains(listener)) {
|
||||
throw new IllegalArgumentException("Listener already registered");
|
||||
}
|
||||
if (mChangeListeners.size() == 0) {
|
||||
try {
|
||||
sService.requestThemeChangeUpdates(mThemeChangeListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to register listener", e);
|
||||
}
|
||||
}
|
||||
mChangeListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a {@link ThemeChangeListener}
|
||||
* @param listener {@link ThemeChangeListener} to unregister
|
||||
*/
|
||||
public void unregisterThemeChangeListener(ThemeChangeListener listener) {
|
||||
synchronized (mChangeListeners) {
|
||||
mChangeListeners.remove(listener);
|
||||
if (mChangeListeners.size() == 0) {
|
||||
try {
|
||||
sService.removeUpdates(mThemeChangeListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to unregister listener", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link ThemeProcessingListener} to be notified when a theme is done being
|
||||
* processed.
|
||||
* @param listener {@link ThemeProcessingListener} to register
|
||||
*/
|
||||
public void registerProcessingListener(ThemeProcessingListener listener) {
|
||||
synchronized (mProcessingListeners) {
|
||||
if (mProcessingListeners.contains(listener)) {
|
||||
throw new IllegalArgumentException("Listener already registered");
|
||||
}
|
||||
if (mProcessingListeners.size() == 0) {
|
||||
try {
|
||||
sService.registerThemeProcessingListener(mThemeProcessingListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to register listener", e);
|
||||
}
|
||||
}
|
||||
mProcessingListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a {@link ThemeProcessingListener}.
|
||||
* @param listener {@link ThemeProcessingListener} to unregister
|
||||
*/
|
||||
public void unregisterProcessingListener(ThemeChangeListener listener) {
|
||||
synchronized (mProcessingListeners) {
|
||||
mProcessingListeners.remove(listener);
|
||||
if (mProcessingListeners.size() == 0) {
|
||||
try {
|
||||
sService.unregisterThemeProcessingListener(mThemeProcessingListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to unregister listener", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void requestThemeChange(String pkgName, List<String> components) {
|
||||
requestThemeChange(pkgName, components, true);
|
||||
}
|
||||
|
||||
public void requestThemeChange(String pkgName, List<String> components,
|
||||
boolean removePerAppThemes) {
|
||||
Map<String, String> componentMap = new HashMap<>(components.size());
|
||||
for (String component : components) {
|
||||
componentMap.put(component, pkgName);
|
||||
}
|
||||
requestThemeChange(componentMap, removePerAppThemes);
|
||||
}
|
||||
|
||||
public void requestThemeChange(Map<String, String> componentMap) {
|
||||
requestThemeChange(componentMap, true);
|
||||
}
|
||||
|
||||
public void requestThemeChange(Map<String, String> componentMap, boolean removePerAppThemes) {
|
||||
ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
|
||||
for (String component : componentMap.keySet()) {
|
||||
builder.setComponent(component, componentMap.get(component));
|
||||
}
|
||||
|
||||
requestThemeChange(builder.build(), removePerAppThemes);
|
||||
}
|
||||
|
||||
public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes) {
|
||||
try {
|
||||
sService.requestThemeChange(request, removePerAppThemes);
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyDefaultTheme() {
|
||||
try {
|
||||
sService.applyDefaultTheme();
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isThemeApplying() {
|
||||
try {
|
||||
return sService.isThemeApplying();
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isThemeBeingProcessed(String themePkgName) {
|
||||
try {
|
||||
return sService.isThemeBeingProcessed(themePkgName);
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
try {
|
||||
return sService.getProgress();
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean processThemeResources(String themePkgName) {
|
||||
try {
|
||||
return sService.processThemeResources(themePkgName);
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getLastThemeChangeTime() {
|
||||
try {
|
||||
return sService.getLastThemeChangeTime();
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ThemeChangeRequest.RequestType getLastThemeChangeRequestType() {
|
||||
try {
|
||||
int type = sService.getLastThemeChangeRequestType();
|
||||
return (type >= 0 && type < RequestType.values().length)
|
||||
? RequestType.values()[type]
|
||||
: null;
|
||||
} catch (RemoteException e) {
|
||||
logThemeServiceException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void logThemeServiceException(Exception e) {
|
||||
Log.w(TAG, "Unable to access ThemeService", e);
|
||||
}
|
||||
|
||||
public interface ThemeChangeListener {
|
||||
void onProgress(int progress);
|
||||
void onFinish(boolean isSuccess);
|
||||
}
|
||||
|
||||
public interface ThemeProcessingListener {
|
||||
void onFinishedProcessing(String pkgName);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.internal.themes;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
/** @hide */
|
||||
interface IIconCacheManager {
|
||||
boolean cacheComposedIcon(in Bitmap icon, String path);
|
||||
}
|
332
src/java/org/cyanogenmod/internal/util/ImageUtils.java
Normal file
332
src/java/org/cyanogenmod/internal/util/ImageUtils.java
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2014 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.internal.util;
|
||||
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.webkit.URLUtil;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import cyanogenmod.providers.ThemesContract.PreviewColumns;
|
||||
import cyanogenmod.providers.ThemesContract.ThemesColumns;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
public class ImageUtils {
|
||||
private static final String TAG = ImageUtils.class.getSimpleName();
|
||||
|
||||
private static final String ASSET_URI_PREFIX = "file:///android_asset/";
|
||||
private static final int DEFAULT_IMG_QUALITY = 100;
|
||||
|
||||
/**
|
||||
* Gets the Width and Height of the image
|
||||
*
|
||||
* @param inputStream The input stream of the image
|
||||
*
|
||||
* @return A point structure that holds the Width and Height (x and y)/*"
|
||||
*/
|
||||
public static Point getImageDimension(InputStream inputStream) {
|
||||
if (inputStream == null) {
|
||||
throw new IllegalArgumentException("'inputStream' cannot be null!");
|
||||
}
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(inputStream, null, options);
|
||||
Point point = new Point(options.outWidth,options.outHeight);
|
||||
return point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the input image and returns a new InputStream of the cropped area
|
||||
*
|
||||
* @param inputStream The input stream of the image
|
||||
* @param imageWidth Width of the input image
|
||||
* @param imageHeight Height of the input image
|
||||
* @param inputStream Desired Width
|
||||
* @param inputStream Desired Width
|
||||
*
|
||||
* @return a new InputStream of the cropped area/*"
|
||||
*/
|
||||
public static InputStream cropImage(InputStream inputStream, int imageWidth, int imageHeight,
|
||||
int outWidth, int outHeight) throws IllegalArgumentException {
|
||||
if (inputStream == null){
|
||||
throw new IllegalArgumentException("inputStream cannot be null");
|
||||
}
|
||||
|
||||
if (imageWidth <= 0 || imageHeight <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("imageWidth and imageHeight must be > 0: imageWidth=%d" +
|
||||
" imageHeight=%d", imageWidth, imageHeight));
|
||||
}
|
||||
|
||||
if (outWidth <= 0 || outHeight <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("outWidth and outHeight must be > 0: outWidth=%d" +
|
||||
" outHeight=%d", imageWidth, outHeight));
|
||||
}
|
||||
|
||||
int scaleDownSampleSize = Math.min(imageWidth / outWidth, imageHeight / outHeight);
|
||||
if (scaleDownSampleSize > 0) {
|
||||
imageWidth /= scaleDownSampleSize;
|
||||
imageHeight /= scaleDownSampleSize;
|
||||
} else {
|
||||
float ratio = (float) outWidth / outHeight;
|
||||
if (imageWidth < imageHeight * ratio) {
|
||||
outWidth = imageWidth;
|
||||
outHeight = (int) (outWidth / ratio);
|
||||
} else {
|
||||
outHeight = imageHeight;
|
||||
outWidth = (int) (outHeight * ratio);
|
||||
}
|
||||
}
|
||||
int left = (imageWidth - outWidth) / 2;
|
||||
int top = (imageHeight - outHeight) / 2;
|
||||
InputStream compressed = null;
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
if (scaleDownSampleSize > 1) {
|
||||
options.inSampleSize = scaleDownSampleSize;
|
||||
}
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
Bitmap cropped = Bitmap.createBitmap(bitmap, left, top, outWidth, outHeight);
|
||||
ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
|
||||
if (cropped.compress(Bitmap.CompressFormat.PNG, DEFAULT_IMG_QUALITY, tmpOut)) {
|
||||
byte[] outByteArray = tmpOut.toByteArray();
|
||||
compressed = new ByteArrayInputStream(outByteArray);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception " + e);
|
||||
}
|
||||
return compressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the lock screen image and returns a new InputStream of the cropped area
|
||||
*
|
||||
* @param pkgName Name of the theme package
|
||||
* @param context The context
|
||||
*
|
||||
* @return a new InputStream of the cropped image/*"
|
||||
*/
|
||||
public static InputStream getCroppedKeyguardStream(String pkgName, Context context)
|
||||
throws IllegalArgumentException {
|
||||
if (TextUtils.isEmpty(pkgName)) {
|
||||
throw new IllegalArgumentException("'pkgName' cannot be null or empty!");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("'context' cannot be null!");
|
||||
}
|
||||
|
||||
InputStream cropped = null;
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = getOriginalKeyguardStream(pkgName, context);
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
Point point = getImageDimension(stream);
|
||||
IoUtils.closeQuietly(stream);
|
||||
if (point == null || point.x == 0 || point.y == 0) {
|
||||
return null;
|
||||
}
|
||||
WallpaperManager wm = WallpaperManager.getInstance(context);
|
||||
int outWidth = wm.getDesiredMinimumWidth();
|
||||
int outHeight = wm.getDesiredMinimumHeight();
|
||||
stream = getOriginalKeyguardStream(pkgName, context);
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
cropped = cropImage(stream, point.x, point.y, outWidth, outHeight);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception " + e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(stream);
|
||||
}
|
||||
return cropped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the wallpaper image and returns a new InputStream of the cropped area
|
||||
*
|
||||
* @param pkgName Name of the theme package
|
||||
* @param context The context
|
||||
*
|
||||
* @return a new InputStream of the cropped image/*"
|
||||
*/
|
||||
public static InputStream getCroppedWallpaperStream(String pkgName, long wallpaperId,
|
||||
Context context) {
|
||||
if (TextUtils.isEmpty(pkgName)) {
|
||||
throw new IllegalArgumentException("'pkgName' cannot be null or empty!");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("'context' cannot be null!");
|
||||
}
|
||||
|
||||
InputStream cropped = null;
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = getOriginalWallpaperStream(pkgName, wallpaperId, context);
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
Point point = getImageDimension(stream);
|
||||
IoUtils.closeQuietly(stream);
|
||||
if (point == null || point.x == 0 || point.y == 0) {
|
||||
return null;
|
||||
}
|
||||
WallpaperManager wm = WallpaperManager.getInstance(context);
|
||||
int outWidth = wm.getDesiredMinimumWidth();
|
||||
int outHeight = wm.getDesiredMinimumHeight();
|
||||
stream = getOriginalWallpaperStream(pkgName, wallpaperId, context);
|
||||
if (stream == null) {
|
||||
return null;
|
||||
}
|
||||
cropped = cropImage(stream, point.x, point.y, outWidth, outHeight);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception " + e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(stream);
|
||||
}
|
||||
return cropped;
|
||||
}
|
||||
|
||||
private static InputStream getOriginalKeyguardStream(String pkgName, Context context) {
|
||||
if (TextUtils.isEmpty(pkgName) || context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
//Get input WP stream from the theme
|
||||
Context themeCtx = context.createPackageContext(pkgName,
|
||||
Context.CONTEXT_IGNORE_SECURITY);
|
||||
AssetManager assetManager = themeCtx.getAssets();
|
||||
String wpPath = ThemeUtils.getLockscreenWallpaperPath(assetManager);
|
||||
if (wpPath == null) {
|
||||
Log.w(TAG, "Not setting lockscreen wp because wallpaper file was not found.");
|
||||
} else {
|
||||
inputStream = ThemeUtils.getInputStreamFromAsset(themeCtx,
|
||||
ASSET_URI_PREFIX + wpPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "There was an error setting lockscreen wp for pkg " + pkgName, e);
|
||||
}
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
private static InputStream getOriginalWallpaperStream(String pkgName, long componentId,
|
||||
Context context) {
|
||||
String wpPath;
|
||||
if (TextUtils.isEmpty(pkgName) || context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream inputStream = null;
|
||||
String selection = ThemesColumns.PKG_NAME + "= ?";
|
||||
String[] selectionArgs = {pkgName};
|
||||
Cursor c = context.getContentResolver().query(ThemesColumns.CONTENT_URI,
|
||||
null, selection,
|
||||
selectionArgs, null);
|
||||
if (c == null || c.getCount() < 1) {
|
||||
if (c != null) c.close();
|
||||
return null;
|
||||
} else {
|
||||
c.moveToFirst();
|
||||
}
|
||||
|
||||
try {
|
||||
Context themeContext = context.createPackageContext(pkgName,
|
||||
Context.CONTEXT_IGNORE_SECURITY);
|
||||
boolean isLegacyTheme = c.getInt(
|
||||
c.getColumnIndex(ThemesColumns.IS_LEGACY_THEME)) == 1;
|
||||
String wallpaper = c.getString(
|
||||
c.getColumnIndex(ThemesColumns.WALLPAPER_URI));
|
||||
if (wallpaper != null) {
|
||||
if (URLUtil.isAssetUrl(wallpaper)) {
|
||||
inputStream = ThemeUtils.getInputStreamFromAsset(themeContext, wallpaper);
|
||||
} else {
|
||||
inputStream = context.getContentResolver().openInputStream(
|
||||
Uri.parse(wallpaper));
|
||||
}
|
||||
} else {
|
||||
// try and get the wallpaper directly from the apk if the URI was null
|
||||
Context themeCtx = context.createPackageContext(pkgName,
|
||||
Context.CONTEXT_IGNORE_SECURITY);
|
||||
AssetManager assetManager = themeCtx.getAssets();
|
||||
wpPath = queryWpPathFromComponentId(context, pkgName, componentId);
|
||||
if (wpPath == null) wpPath = ThemeUtils.getWallpaperPath(assetManager);
|
||||
if (wpPath == null) {
|
||||
Log.e(TAG, "Not setting wp because wallpaper file was not found.");
|
||||
} else {
|
||||
inputStream = ThemeUtils.getInputStreamFromAsset(themeCtx,
|
||||
ASSET_URI_PREFIX + wpPath);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "getWallpaperStream: " + e);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
private static String queryWpPathFromComponentId(Context context, String pkgName,
|
||||
long componentId) {
|
||||
String wpPath = null;
|
||||
String[] projection = new String[] { PreviewColumns.COL_VALUE };
|
||||
String selection = ThemesColumns.PKG_NAME + "=? AND " +
|
||||
PreviewColumns.COMPONENT_ID + "=? AND " +
|
||||
PreviewColumns.COL_KEY + "=?";
|
||||
String[] selectionArgs = new String[] {
|
||||
pkgName,
|
||||
Long.toString(componentId),
|
||||
PreviewColumns.WALLPAPER_FULL
|
||||
};
|
||||
|
||||
Cursor c = context.getContentResolver()
|
||||
.query(PreviewColumns.COMPONENTS_URI,
|
||||
projection, selection, selectionArgs, null);
|
||||
if (c != null) {
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
int valIdx = c.getColumnIndex(PreviewColumns.COL_VALUE);
|
||||
wpPath = c.getString(valIdx);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, "Could not get wallpaper path", e);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
return wpPath;
|
||||
}
|
||||
}
|
||||
|
687
src/java/org/cyanogenmod/internal/util/ThemeUtils.java
Normal file
687
src/java/org/cyanogenmod/internal/util/ThemeUtils.java
Normal file
@ -0,0 +1,687 @@
|
||||
/*
|
||||
* 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.internal.util;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.ThemeConfig;
|
||||
import android.database.Cursor;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.FileUtils;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
|
||||
import android.view.WindowManager;
|
||||
import cyanogenmod.providers.CMSettings;
|
||||
import cyanogenmod.providers.ThemesContract.ThemesColumns;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static android.content.res.ThemeConfig.SYSTEM_DEFAULT;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ThemeUtils {
|
||||
private static final String TAG = ThemeUtils.class.getSimpleName();
|
||||
|
||||
// Package name for any app which does not have a specific theme applied
|
||||
private static final String DEFAULT_PKG = "default";
|
||||
|
||||
private static final Set<String> SUPPORTED_THEME_COMPONENTS = new ArraySet<>();
|
||||
|
||||
static {
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_ALARMS);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_BOOT_ANIM);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_FONTS);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_ICONS);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_LAUNCHER);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_LOCKSCREEN);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_NAVIGATION_BAR);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_NOTIFICATIONS);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_OVERLAYS);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_RINGTONES);
|
||||
SUPPORTED_THEME_COMPONENTS.add(ThemesColumns.MODIFIES_STATUS_BAR);
|
||||
}
|
||||
|
||||
// Constants for theme change broadcast
|
||||
public static final String ACTION_THEME_CHANGED = "org.cyanogenmod.intent.action.THEME_CHANGED";
|
||||
public static final String EXTRA_COMPONENTS = "components";
|
||||
public static final String EXTRA_REQUEST_TYPE = "request_type";
|
||||
public static final String EXTRA_UPDATE_TIME = "update_time";
|
||||
|
||||
// path to asset lockscreen and wallpapers directory
|
||||
public static final String LOCKSCREEN_WALLPAPER_PATH = "lockscreen";
|
||||
public static final String WALLPAPER_PATH = "wallpapers";
|
||||
|
||||
// path to external theme resources, i.e. bootanimation.zip
|
||||
public static final String SYSTEM_THEME_PATH = "/data/system/theme";
|
||||
public static final String SYSTEM_THEME_FONT_PATH = SYSTEM_THEME_PATH + File.separator + "fonts";
|
||||
public static final String SYSTEM_THEME_RINGTONE_PATH = SYSTEM_THEME_PATH
|
||||
+ File.separator + "ringtones";
|
||||
public static final String SYSTEM_THEME_NOTIFICATION_PATH = SYSTEM_THEME_PATH
|
||||
+ File.separator + "notifications";
|
||||
public static final String SYSTEM_THEME_ALARM_PATH = SYSTEM_THEME_PATH
|
||||
+ File.separator + "alarms";
|
||||
public static final String SYSTEM_THEME_ICON_CACHE_DIR = SYSTEM_THEME_PATH
|
||||
+ File.separator + "icons";
|
||||
// internal path to bootanimation.zip inside theme apk
|
||||
public static final String THEME_BOOTANIMATION_PATH = "assets/bootanimation/bootanimation.zip";
|
||||
|
||||
public static final String SYSTEM_MEDIA_PATH = "/system/media/audio";
|
||||
public static final String SYSTEM_ALARMS_PATH = SYSTEM_MEDIA_PATH + File.separator
|
||||
+ "alarms";
|
||||
public static final String SYSTEM_RINGTONES_PATH = SYSTEM_MEDIA_PATH + File.separator
|
||||
+ "ringtones";
|
||||
public static final String SYSTEM_NOTIFICATIONS_PATH = SYSTEM_MEDIA_PATH + File.separator
|
||||
+ "notifications";
|
||||
|
||||
private static final String MEDIA_CONTENT_URI = "content://media/internal/audio/media";
|
||||
|
||||
public static final int SYSTEM_TARGET_API = 0;
|
||||
|
||||
/* Path to cached theme resources */
|
||||
public static final String RESOURCE_CACHE_DIR = "/data/resource-cache/";
|
||||
|
||||
/* Path inside a theme APK to the overlay folder */
|
||||
public static final String OVERLAY_PATH = "assets/overlays/";
|
||||
public static final String ICONS_PATH = "assets/icons/";
|
||||
public static final String COMMON_RES_PATH = "assets/overlays/common/";
|
||||
|
||||
public static final String IDMAP_SUFFIX = "@idmap";
|
||||
public static final String COMMON_RES_TARGET = "common";
|
||||
|
||||
public static final String ICON_HASH_FILENAME = "hash";
|
||||
|
||||
public static final String FONT_XML = "fonts.xml";
|
||||
|
||||
public 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable list of all theme components
|
||||
* @return
|
||||
*/
|
||||
public static List<String> getAllComponents() {
|
||||
List<String> components = new ArrayList<>(SUPPORTED_THEME_COMPONENTS.size());
|
||||
components.addAll(SUPPORTED_THEME_COMPONENTS);
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable list of all the theme components supported by a given package
|
||||
* NOTE: This queries the themes content provider. If there isn't a provider installed
|
||||
* or if it is too early in the boot process this method will not work.
|
||||
*/
|
||||
public static List<String> getSupportedComponents(Context context, String pkgName) {
|
||||
List<String> supportedComponents = new ArrayList<>();
|
||||
|
||||
String selection = ThemesColumns.PKG_NAME + "= ?";
|
||||
String[] selectionArgs = new String[]{ pkgName };
|
||||
Cursor c = context.getContentResolver().query(ThemesColumns.CONTENT_URI,
|
||||
null, selection, selectionArgs, null);
|
||||
|
||||
if (c != null) {
|
||||
if (c.moveToFirst()) {
|
||||
List<String> allComponents = getAllComponents();
|
||||
for (String component : allComponents) {
|
||||
int index = c.getColumnIndex(component);
|
||||
if (c.getInt(index) == 1) {
|
||||
supportedComponents.add(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
return supportedComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the components from the default theme. If the default theme is not SYSTEM then any
|
||||
* components that are not in the default theme will come from SYSTEM to create a complete
|
||||
* component map.
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, String> getDefaultComponents(Context context) {
|
||||
String defaultThemePkg = getDefaultThemePackageName(context);
|
||||
List<String> defaultComponents = null;
|
||||
List<String> systemComponents = getSupportedComponents(context, SYSTEM_DEFAULT);
|
||||
if (!DEFAULT_PKG.equals(defaultThemePkg)) {
|
||||
defaultComponents = getSupportedComponents(context, defaultThemePkg);
|
||||
}
|
||||
|
||||
Map<String, String> componentMap = new HashMap<>(systemComponents.size());
|
||||
if (defaultComponents != null) {
|
||||
for (String component : defaultComponents) {
|
||||
componentMap.put(component, defaultThemePkg);
|
||||
}
|
||||
}
|
||||
for (String component : systemComponents) {
|
||||
if (!componentMap.containsKey(component)) {
|
||||
componentMap.put(component, SYSTEM_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
return componentMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the icons for the given theme
|
||||
* @param pkgName
|
||||
* @return
|
||||
*/
|
||||
public static String getIconPackDir(String pkgName) {
|
||||
return getOverlayResourceCacheDir(pkgName) + File.separator + "icons";
|
||||
}
|
||||
|
||||
public static String getIconHashFile(String pkgName) {
|
||||
return getIconPackDir(pkgName) + File.separator + ICON_HASH_FILENAME;
|
||||
}
|
||||
|
||||
public static String getIconPackApkPath(String pkgName) {
|
||||
return getIconPackDir(pkgName) + "/resources.apk";
|
||||
}
|
||||
|
||||
public static String getIconPackResPath(String pkgName) {
|
||||
return getIconPackDir(pkgName) + "/resources.arsc";
|
||||
}
|
||||
|
||||
public static String getIdmapPath(String targetPkgName, String overlayPkgName) {
|
||||
return getTargetCacheDir(targetPkgName, overlayPkgName) + File.separator + "idmap";
|
||||
}
|
||||
|
||||
public static String getOverlayPathToTarget(String targetPkgName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(OVERLAY_PATH);
|
||||
sb.append(targetPkgName);
|
||||
sb.append('/');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getCommonPackageName(String themePackageName) {
|
||||
if (TextUtils.isEmpty(themePackageName)) return null;
|
||||
|
||||
return COMMON_RES_TARGET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_THEME_PATH directory if it does not exist
|
||||
*/
|
||||
public static void createThemeDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_FONT_PATH directory if it does not exist
|
||||
*/
|
||||
public static void createFontDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_FONT_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_THEME_RINGTONE_PATH directory if it does not exist
|
||||
*/
|
||||
public static void createRingtoneDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_RINGTONE_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_THEME_NOTIFICATION_PATH directory if it does not exist
|
||||
*/
|
||||
public static void createNotificationDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_NOTIFICATION_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_THEME_ALARM_PATH directory if it does not exist
|
||||
*/
|
||||
public static void createAlarmDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_ALARM_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SYSTEM_THEME_ICON_CACHE_DIR directory if it does not exist
|
||||
*/
|
||||
public static void createIconCacheDirIfNotExists() {
|
||||
createDirIfNotExists(SYSTEM_THEME_ICON_CACHE_DIR);
|
||||
}
|
||||
|
||||
public static void createCacheDirIfNotExists() throws IOException {
|
||||
File file = new File(RESOURCE_CACHE_DIR);
|
||||
if (!file.exists() && !file.mkdir()) {
|
||||
throw new IOException("Could not create dir: " + file.toString());
|
||||
}
|
||||
FileUtils.setPermissions(file, FileUtils.S_IRWXU
|
||||
| FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
|
||||
}
|
||||
|
||||
public static void createResourcesDirIfNotExists(String targetPkgName, String overlayPkgName)
|
||||
throws IOException {
|
||||
createDirIfNotExists(getOverlayResourceCacheDir(overlayPkgName));
|
||||
File file = new File(getTargetCacheDir(targetPkgName, overlayPkgName));
|
||||
if (!file.exists() && !file.mkdir()) {
|
||||
throw new IOException("Could not create dir: " + file.toString());
|
||||
}
|
||||
FileUtils.setPermissions(file, FileUtils.S_IRWXU
|
||||
| FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
|
||||
}
|
||||
|
||||
public static void createIconDirIfNotExists(String pkgName) throws IOException {
|
||||
createDirIfNotExists(getOverlayResourceCacheDir(pkgName));
|
||||
File file = new File(getIconPackDir(pkgName));
|
||||
if (!file.exists() && !file.mkdir()) {
|
||||
throw new IOException("Could not create dir: " + file.toString());
|
||||
}
|
||||
FileUtils.setPermissions(file, FileUtils.S_IRWXU
|
||||
| FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
|
||||
}
|
||||
|
||||
public static void clearIconCache() {
|
||||
FileUtils.deleteContents(new File(SYSTEM_THEME_ICON_CACHE_DIR));
|
||||
}
|
||||
|
||||
public static void registerThemeChangeReceiver(final Context context,
|
||||
final BroadcastReceiver receiver) {
|
||||
IntentFilter filter = new IntentFilter(ACTION_THEME_CHANGED);
|
||||
|
||||
context.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
public static String getLockscreenWallpaperPath(AssetManager assetManager) throws IOException {
|
||||
String[] assets = assetManager.list(LOCKSCREEN_WALLPAPER_PATH);
|
||||
String asset = getFirstNonEmptyAsset(assets);
|
||||
if (asset == null) return null;
|
||||
return LOCKSCREEN_WALLPAPER_PATH + File.separator + asset;
|
||||
}
|
||||
|
||||
public static String getWallpaperPath(AssetManager assetManager) throws IOException {
|
||||
String[] assets = assetManager.list(WALLPAPER_PATH);
|
||||
String asset = getFirstNonEmptyAsset(assets);
|
||||
if (asset == null) return null;
|
||||
return WALLPAPER_PATH + File.separator + asset;
|
||||
}
|
||||
|
||||
public static List<String> getWallpaperPathList(AssetManager assetManager)
|
||||
throws IOException {
|
||||
List<String> wallpaperList = new ArrayList<String>();
|
||||
String[] assets = assetManager.list(WALLPAPER_PATH);
|
||||
for (String asset : assets) {
|
||||
if (!TextUtils.isEmpty(asset)) {
|
||||
wallpaperList.add(WALLPAPER_PATH + File.separator + asset);
|
||||
}
|
||||
}
|
||||
return wallpaperList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root path of the resource cache for the given theme
|
||||
* @param themePkgName
|
||||
* @return Root resource cache path for the given theme
|
||||
*/
|
||||
public static String getOverlayResourceCacheDir(String themePkgName) {
|
||||
return RESOURCE_CACHE_DIR + themePkgName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the resource cache for the given target and theme
|
||||
* @param targetPkgName
|
||||
* @param themePkg
|
||||
* @return Path to the resource cache for this target and theme
|
||||
*/
|
||||
public static String getTargetCacheDir(String targetPkgName, PackageInfo themePkg) {
|
||||
return getTargetCacheDir(targetPkgName, themePkg.packageName);
|
||||
}
|
||||
|
||||
public static String getTargetCacheDir(String targetPkgName, PackageParser.Package themePkg) {
|
||||
return getTargetCacheDir(targetPkgName, themePkg.packageName);
|
||||
}
|
||||
|
||||
public static String getTargetCacheDir(String targetPkgName, String themePkgName) {
|
||||
return getOverlayResourceCacheDir(themePkgName) + File.separator + targetPkgName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a theme'd context using the overlay applied to SystemUI
|
||||
* @param context Base context
|
||||
* @return Themed context
|
||||
*/
|
||||
public static Context createUiContext(final Context context) {
|
||||
try {
|
||||
Context uiContext = context.createPackageContext("com.android.systemui",
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
return new ThemedUiContext(uiContext, context.getApplicationContext());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the boot animation to better fit the device by editing the desc.txt found
|
||||
* in the bootanimation.zip
|
||||
* @param context Context to use for getting an instance of the WindowManager
|
||||
* @param input InputStream of the original bootanimation.zip
|
||||
* @param dst Path to store the newly created bootanimation.zip
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void copyAndScaleBootAnimation(Context context, InputStream input, String dst)
|
||||
throws IOException {
|
||||
final OutputStream os = new FileOutputStream(dst);
|
||||
final ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(os));
|
||||
final ZipInputStream bootAni = new ZipInputStream(new BufferedInputStream(input));
|
||||
ZipEntry ze;
|
||||
|
||||
zos.setMethod(ZipOutputStream.STORED);
|
||||
final byte[] bytes = new byte[4096];
|
||||
int len;
|
||||
while ((ze = bootAni.getNextEntry()) != null) {
|
||||
ZipEntry entry = new ZipEntry(ze.getName());
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
entry.setCrc(ze.getCrc());
|
||||
entry.setSize(ze.getSize());
|
||||
entry.setCompressedSize(ze.getSize());
|
||||
if (!ze.getName().equals("desc.txt")) {
|
||||
// just copy this entry straight over into the output zip
|
||||
zos.putNextEntry(entry);
|
||||
while ((len = bootAni.read(bytes)) > 0) {
|
||||
zos.write(bytes, 0, len);
|
||||
}
|
||||
} else {
|
||||
String line;
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(bootAni));
|
||||
final String[] info = reader.readLine().split(" ");
|
||||
|
||||
int scaledWidth;
|
||||
int scaledHeight;
|
||||
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getRealMetrics(dm);
|
||||
// just in case the device is in landscape orientation we will
|
||||
// swap the values since most (if not all) animations are portrait
|
||||
if (dm.widthPixels > dm.heightPixels) {
|
||||
scaledWidth = dm.heightPixels;
|
||||
scaledHeight = dm.widthPixels;
|
||||
} else {
|
||||
scaledWidth = dm.widthPixels;
|
||||
scaledHeight = dm.heightPixels;
|
||||
}
|
||||
|
||||
int width = Integer.parseInt(info[0]);
|
||||
int height = Integer.parseInt(info[1]);
|
||||
|
||||
if (width == height)
|
||||
scaledHeight = scaledWidth;
|
||||
else {
|
||||
// adjust scaledHeight to retain original aspect ratio
|
||||
float scale = (float)scaledWidth / (float)width;
|
||||
int newHeight = (int)((float)height * scale);
|
||||
if (newHeight < scaledHeight)
|
||||
scaledHeight = newHeight;
|
||||
}
|
||||
|
||||
CRC32 crc32 = new CRC32();
|
||||
int size = 0;
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
line = String.format("%d %d %s\n", scaledWidth, scaledHeight, info[2]);
|
||||
buffer.put(line.getBytes());
|
||||
size += line.getBytes().length;
|
||||
crc32.update(line.getBytes());
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = String.format("%s\n", line);
|
||||
buffer.put(line.getBytes());
|
||||
size += line.getBytes().length;
|
||||
crc32.update(line.getBytes());
|
||||
}
|
||||
entry.setCrc(crc32.getValue());
|
||||
entry.setSize(size);
|
||||
entry.setCompressedSize(size);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(buffer.array(), 0, size);
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
zos.close();
|
||||
}
|
||||
|
||||
public static boolean isValidAudible(String fileName) {
|
||||
return (fileName != null &&
|
||||
(fileName.endsWith(".mp3") || fileName.endsWith(".ogg")));
|
||||
}
|
||||
|
||||
public static boolean setAudible(Context context, File ringtone, int type, String name) {
|
||||
final String path = ringtone.getAbsolutePath();
|
||||
final String mimeType = name.endsWith(".ogg") ? "audio/ogg" : "audio/mp3";
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.MediaColumns.DATA, path);
|
||||
values.put(MediaStore.MediaColumns.TITLE, name);
|
||||
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
|
||||
values.put(MediaStore.MediaColumns.SIZE, ringtone.length());
|
||||
values.put(MediaStore.Audio.Media.IS_RINGTONE, type == RingtoneManager.TYPE_RINGTONE);
|
||||
values.put(MediaStore.Audio.Media.IS_NOTIFICATION,
|
||||
type == RingtoneManager.TYPE_NOTIFICATION);
|
||||
values.put(MediaStore.Audio.Media.IS_ALARM, type == RingtoneManager.TYPE_ALARM);
|
||||
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
|
||||
|
||||
Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
|
||||
Uri newUri = null;
|
||||
Cursor c = context.getContentResolver().query(uri,
|
||||
new String[] {MediaStore.MediaColumns._ID},
|
||||
MediaStore.MediaColumns.DATA + "='" + path + "'",
|
||||
null, null);
|
||||
if (c != null && c.getCount() > 0) {
|
||||
c.moveToFirst();
|
||||
long id = c.getLong(0);
|
||||
c.close();
|
||||
newUri = Uri.withAppendedPath(Uri.parse(MEDIA_CONTENT_URI), "" + id);
|
||||
context.getContentResolver().update(uri, values,
|
||||
MediaStore.MediaColumns._ID + "=" + id, null);
|
||||
}
|
||||
if (newUri == null)
|
||||
newUri = context.getContentResolver().insert(uri, values);
|
||||
try {
|
||||
RingtoneManager.setActualDefaultRingtoneUri(context, type, newUri);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean setDefaultAudible(Context context, int type) {
|
||||
final String audiblePath = getDefaultAudiblePath(type);
|
||||
if (audiblePath != null) {
|
||||
Uri uri = MediaStore.Audio.Media.getContentUriForPath(audiblePath);
|
||||
Cursor c = context.getContentResolver().query(uri,
|
||||
new String[] {MediaStore.MediaColumns._ID},
|
||||
MediaStore.MediaColumns.DATA + "='" + audiblePath + "'",
|
||||
null, null);
|
||||
if (c != null && c.getCount() > 0) {
|
||||
c.moveToFirst();
|
||||
long id = c.getLong(0);
|
||||
c.close();
|
||||
uri = Uri.withAppendedPath(
|
||||
Uri.parse(MEDIA_CONTENT_URI), "" + id);
|
||||
}
|
||||
if (uri != null)
|
||||
RingtoneManager.setActualDefaultRingtoneUri(context, type, uri);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getDefaultAudiblePath(int type) {
|
||||
final String name;
|
||||
final String path;
|
||||
switch (type) {
|
||||
case RingtoneManager.TYPE_ALARM:
|
||||
name = SystemProperties.get("ro.config.alarm_alert", null);
|
||||
path = name != null ? SYSTEM_ALARMS_PATH + File.separator + name : null;
|
||||
break;
|
||||
case RingtoneManager.TYPE_NOTIFICATION:
|
||||
name = SystemProperties.get("ro.config.notification_sound", null);
|
||||
path = name != null ? SYSTEM_NOTIFICATIONS_PATH + File.separator + name : null;
|
||||
break;
|
||||
case RingtoneManager.TYPE_RINGTONE:
|
||||
name = SystemProperties.get("ro.config.ringtone", null);
|
||||
path = name != null ? SYSTEM_RINGTONES_PATH + File.separator + name : null;
|
||||
break;
|
||||
default:
|
||||
path = null;
|
||||
break;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static void clearAudibles(Context context, String audiblePath) {
|
||||
final File audibleDir = new File(audiblePath);
|
||||
if (audibleDir.exists()) {
|
||||
String[] files = audibleDir.list();
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
for (String s : files) {
|
||||
final String filePath = audiblePath + File.separator + s;
|
||||
Uri uri = MediaStore.Audio.Media.getContentUriForPath(filePath);
|
||||
resolver.delete(uri, MediaStore.MediaColumns.DATA + "=\""
|
||||
+ filePath + "\"", null);
|
||||
(new File(filePath)).delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream getInputStreamFromAsset(Context ctx, String path) throws IOException {
|
||||
if (ctx == null || path == null) return null;
|
||||
|
||||
InputStream is;
|
||||
String ASSET_BASE = "file:///android_asset/";
|
||||
path = path.substring(ASSET_BASE.length());
|
||||
AssetManager assets = ctx.getAssets();
|
||||
is = assets.open(path);
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to determine if a theme component is a per app theme and not a standard
|
||||
* component.
|
||||
* @param component
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPerAppThemeComponent(String component) {
|
||||
return !(DEFAULT_PKG.equals(component)
|
||||
|| ThemeConfig.SYSTEMUI_STATUS_BAR_PKG.equals(component)
|
||||
|| ThemeConfig.SYSTEMUI_NAVBAR_PKG.equals(component));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first non-empty asset name. Empty assets can occur if the APK is built
|
||||
* with folders included as zip entries in the APK. Searching for files inside "folderName" via
|
||||
* assetManager.list("folderName") can cause these entries to be included as empty strings.
|
||||
* @param assets
|
||||
* @return
|
||||
*/
|
||||
private static String getFirstNonEmptyAsset(String[] assets) {
|
||||
if (assets == null) return null;
|
||||
String filename = null;
|
||||
for(String asset : assets) {
|
||||
if (!TextUtils.isEmpty(asset)) {
|
||||
filename = asset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
private static boolean dirExists(String dirPath) {
|
||||
final File dir = new File(dirPath);
|
||||
return dir.exists() && dir.isDirectory();
|
||||
}
|
||||
|
||||
private static void createDirIfNotExists(String dirPath) {
|
||||
if (!dirExists(dirPath)) {
|
||||
File dir = new File(dirPath);
|
||||
if (dir.mkdir()) {
|
||||
FileUtils.setPermissions(dir, FileUtils.S_IRWXU |
|
||||
FileUtils.S_IRWXG| FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThemedUiContext extends ContextWrapper {
|
||||
private Context mAppContext;
|
||||
|
||||
public ThemedUiContext(Context context, Context appContext) {
|
||||
super(context);
|
||||
mAppContext = appContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getApplicationContext() {
|
||||
return mAppContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackageName() {
|
||||
return mAppContext.getPackageName();
|
||||
}
|
||||
}
|
||||
}
|
@ -371,8 +371,13 @@ package cyanogenmod.content {
|
||||
ctor public Intent();
|
||||
field public static final java.lang.String ACTION_PROTECTED = "cyanogenmod.intent.action.PACKAGE_PROTECTED";
|
||||
field public static final java.lang.String ACTION_PROTECTED_CHANGED = "cyanogenmod.intent.action.PROTECTED_COMPONENT_UPDATE";
|
||||
field public static final java.lang.String ACTION_THEME_INSTALLED = "cyanogenmod.intent.action.THEME_INSTALLED";
|
||||
field public static final java.lang.String ACTION_THEME_REMOVED = "cyanogenmod.intent.action.THEME_REMOVED";
|
||||
field public static final java.lang.String ACTION_THEME_UPDATED = "cyanogenmod.intent.action.THEME_UPDATED";
|
||||
field public static final java.lang.String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE = "cyanogenmod.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE";
|
||||
field public static final java.lang.String EXTRA_PROTECTED_COMPONENTS = "cyanogenmod.intent.extra.PACKAGE_PROTECTED_COMPONENTS";
|
||||
field public static final java.lang.String EXTRA_PROTECTED_STATE = "cyanogenmod.intent.extra.PACKAGE_PROTECTED_STATE";
|
||||
field public static final java.lang.String URI_SCHEME_PACKAGE = "package";
|
||||
}
|
||||
|
||||
}
|
||||
@ -556,6 +561,7 @@ package cyanogenmod.platform {
|
||||
public static final class Manifest.permission {
|
||||
ctor public Manifest.permission();
|
||||
field public static final java.lang.String ACCESS_APP_SUGGESTIONS = "cyanogenmod.permission.ACCESS_APP_SUGGESTIONS";
|
||||
field public static final java.lang.String ACCESS_THEME_MANAGER = "cyanogenmod.permission.ACCESS_THEME_MANAGER";
|
||||
field public static final java.lang.String HARDWARE_ABSTRACTION_ACCESS = "cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS";
|
||||
field public static final java.lang.String MANAGE_ALARMS = "cyanogenmod.permission.MANAGE_ALARMS";
|
||||
field public static final java.lang.String MANAGE_PERSISTENT_STORAGE = "cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE";
|
||||
@ -567,6 +573,7 @@ package cyanogenmod.platform {
|
||||
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
||||
field public static final java.lang.String READ_ALARMS = "cyanogenmod.permission.READ_ALARMS";
|
||||
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
||||
field public static final java.lang.String READ_THEMES = "cyanogenmod.permission.READ_THEMES";
|
||||
field public static final java.lang.String THIRD_PARTY_KEYGUARD = "android.permission.THIRD_PARTY_KEYGUARD";
|
||||
field public static final java.lang.String WRITE_ALARMS = "cyanogenmod.permission.WRITE_ALARMS";
|
||||
field public static final java.lang.String WRITE_SECURE_SETTINGS = "cyanogenmod.permission.WRITE_SECURE_SETTINGS";
|
||||
@ -878,6 +885,126 @@ package cyanogenmod.providers {
|
||||
field public static final java.lang.String ZEN_PRIORITY_ALLOW_LIGHTS = "zen_priority_allow_lights";
|
||||
}
|
||||
|
||||
public class ThemesContract {
|
||||
ctor public ThemesContract();
|
||||
field public static final java.lang.String AUTHORITY = "com.cyanogenmod.themes";
|
||||
field public static final android.net.Uri AUTHORITY_URI;
|
||||
}
|
||||
|
||||
public static class ThemesContract.MixnMatchColumns {
|
||||
ctor public ThemesContract.MixnMatchColumns();
|
||||
method public static java.lang.String componentToImageColName(java.lang.String);
|
||||
method public static java.lang.String componentToMixNMatchKey(java.lang.String);
|
||||
method public static java.lang.String mixNMatchKeyToComponent(java.lang.String);
|
||||
field public static final java.lang.String COL_COMPONENT_ID = "component_id";
|
||||
field public static final java.lang.String COL_KEY = "key";
|
||||
field public static final java.lang.String COL_PREV_VALUE = "previous_value";
|
||||
field public static final java.lang.String COL_UPDATE_TIME = "update_time";
|
||||
field public static final java.lang.String COL_VALUE = "value";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String KEY_ALARM = "mixnmatch_alarm";
|
||||
field public static final java.lang.String KEY_BOOT_ANIM = "mixnmatch_boot_anim";
|
||||
field public static final java.lang.String KEY_FONT = "mixnmatch_font";
|
||||
field public static final java.lang.String KEY_HOMESCREEN = "mixnmatch_homescreen";
|
||||
field public static final java.lang.String KEY_ICONS = "mixnmatch_icons";
|
||||
field public static final java.lang.String KEY_LIVE_LOCK_SCREEN = "mixnmatch_live_lock_screen";
|
||||
field public static final java.lang.String KEY_LOCKSCREEN = "mixnmatch_lockscreen";
|
||||
field public static final java.lang.String KEY_NAVIGATION_BAR = "mixnmatch_navigation_bar";
|
||||
field public static final java.lang.String KEY_NOTIFICATIONS = "mixnmatch_notifications";
|
||||
field public static final java.lang.String KEY_OVERLAYS = "mixnmatch_overlays";
|
||||
field public static final java.lang.String KEY_RINGTONE = "mixnmatch_ringtone";
|
||||
field public static final java.lang.String KEY_STATUS_BAR = "mixnmatch_status_bar";
|
||||
field public static final java.lang.String[] ROWS;
|
||||
}
|
||||
|
||||
public static class ThemesContract.PreviewColumns {
|
||||
ctor public ThemesContract.PreviewColumns();
|
||||
field public static final android.net.Uri APPLIED_URI;
|
||||
field public static final java.lang.String BOOTANIMATION_THUMBNAIL = "bootanimation_thumbnail";
|
||||
field public static final java.lang.String COL_KEY = "key";
|
||||
field public static final java.lang.String COL_VALUE = "value";
|
||||
field public static final android.net.Uri COMPONENTS_URI;
|
||||
field public static final java.lang.String COMPONENT_ID = "component_id";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String ICON_PREVIEW_1 = "icon_preview_1";
|
||||
field public static final java.lang.String ICON_PREVIEW_2 = "icon_preview_2";
|
||||
field public static final java.lang.String ICON_PREVIEW_3 = "icon_preview_3";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_PREVIEW = "live_lock_screen_preview";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_THUMBNAIL = "live_lock_screen_thumbnail";
|
||||
field public static final java.lang.String LOCK_WALLPAPER_PREVIEW = "lock_wallpaper_preview";
|
||||
field public static final java.lang.String LOCK_WALLPAPER_THUMBNAIL = "lock_wallpaper_thumbnail";
|
||||
field public static final java.lang.String NAVBAR_BACKGROUND = "navbar_background";
|
||||
field public static final java.lang.String NAVBAR_BACK_BUTTON = "navbar_back_button";
|
||||
field public static final java.lang.String NAVBAR_HOME_BUTTON = "navbar_home_button";
|
||||
field public static final java.lang.String NAVBAR_RECENT_BUTTON = "navbar_recent_button";
|
||||
field public static final java.lang.String STATUSBAR_BACKGROUND = "statusbar_background";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_CIRCLE = "statusbar_battery_circle";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_LANDSCAPE = "statusbar_battery_landscape";
|
||||
field public static final java.lang.String STATUSBAR_BATTERY_PORTRAIT = "statusbar_battery_portrait";
|
||||
field public static final java.lang.String STATUSBAR_BLUETOOTH_ICON = "statusbar_bluetooth_icon";
|
||||
field public static final java.lang.String STATUSBAR_CLOCK_TEXT_COLOR = "statusbar_clock_text_color";
|
||||
field public static final java.lang.String STATUSBAR_SIGNAL_ICON = "statusbar_signal_icon";
|
||||
field public static final java.lang.String STATUSBAR_WIFI_COMBO_MARGIN_END = "wifi_combo_margin_end";
|
||||
field public static final java.lang.String STATUSBAR_WIFI_ICON = "statusbar_wifi_icon";
|
||||
field public static final java.lang.String STYLE_PREVIEW = "style_preview";
|
||||
field public static final java.lang.String STYLE_THUMBNAIL = "style_thumbnail";
|
||||
field public static final java.lang.String THEME_ID = "theme_id";
|
||||
field public static final java.lang.String[] VALID_KEYS;
|
||||
field public static final java.lang.String WALLPAPER_FULL = "wallpaper_full";
|
||||
field public static final java.lang.String WALLPAPER_PREVIEW = "wallpaper_preview";
|
||||
field public static final java.lang.String WALLPAPER_THUMBNAIL = "wallpaper_thumbnail";
|
||||
field public static final java.lang.String _ID = "_id";
|
||||
}
|
||||
|
||||
public static class ThemesContract.ThemesColumns {
|
||||
ctor public ThemesContract.ThemesColumns();
|
||||
field public static final java.lang.String AUTHOR = "author";
|
||||
field public static final java.lang.String BOOT_ANIM_URI = "bootanim_uri";
|
||||
field public static final android.net.Uri CONTENT_URI;
|
||||
field public static final java.lang.String DATE_CREATED = "created";
|
||||
field public static final java.lang.String FONT_URI = "font_uri";
|
||||
field public static final java.lang.String HOMESCREEN_URI = "homescreen_uri";
|
||||
field public static final java.lang.String ICON_URI = "icon_uri";
|
||||
field public static final java.lang.String INSTALL_STATE = "install_state";
|
||||
field public static final java.lang.String INSTALL_TIME = "install_time";
|
||||
field public static final java.lang.String IS_DEFAULT_THEME = "is_default_theme";
|
||||
field public static final java.lang.String IS_LEGACY_ICONPACK = "is_legacy_iconpack";
|
||||
field public static final java.lang.String IS_LEGACY_THEME = "is_legacy_theme";
|
||||
field public static final java.lang.String LAST_UPDATE_TIME = "updateTime";
|
||||
field public static final java.lang.String LOCKSCREEN_URI = "lockscreen_uri";
|
||||
field public static final java.lang.String MODIFIES_ALARMS = "mods_alarms";
|
||||
field public static final java.lang.String MODIFIES_BOOT_ANIM = "mods_bootanim";
|
||||
field public static final java.lang.String MODIFIES_FONTS = "mods_fonts";
|
||||
field public static final java.lang.String MODIFIES_ICONS = "mods_icons";
|
||||
field public static final java.lang.String MODIFIES_LAUNCHER = "mods_homescreen";
|
||||
field public static final java.lang.String MODIFIES_LIVE_LOCK_SCREEN = "mods_live_lock_screen";
|
||||
field public static final java.lang.String MODIFIES_LOCKSCREEN = "mods_lockscreen";
|
||||
field public static final java.lang.String MODIFIES_NAVIGATION_BAR = "mods_navigation_bar";
|
||||
field public static final java.lang.String MODIFIES_NOTIFICATIONS = "mods_notifications";
|
||||
field public static final java.lang.String MODIFIES_OVERLAYS = "mods_overlays";
|
||||
field public static final java.lang.String MODIFIES_RINGTONES = "mods_ringtones";
|
||||
field public static final java.lang.String MODIFIES_STATUS_BAR = "mods_status_bar";
|
||||
field public static final java.lang.String OVERLAYS_URI = "overlays_uri";
|
||||
field public static final java.lang.String PKG_NAME = "pkg_name";
|
||||
field public static final java.lang.String PRESENT_AS_THEME = "present_as_theme";
|
||||
field public static final java.lang.String PRIMARY_COLOR = "primary_color";
|
||||
field public static final java.lang.String SECONDARY_COLOR = "secondary_color";
|
||||
field public static final java.lang.String STATUSBAR_URI = "status_uri";
|
||||
field public static final java.lang.String STYLE_URI = "style_uri";
|
||||
field public static final java.lang.String TARGET_API = "target_api";
|
||||
field public static final java.lang.String TITLE = "title";
|
||||
field public static final java.lang.String WALLPAPER_URI = "wallpaper_uri";
|
||||
field public static final java.lang.String _ID = "_id";
|
||||
}
|
||||
|
||||
public static class ThemesContract.ThemesColumns.InstallState {
|
||||
ctor public ThemesContract.ThemesColumns.InstallState();
|
||||
field public static final int INSTALLED = 3; // 0x3
|
||||
field public static final int INSTALLING = 1; // 0x1
|
||||
field public static final int UNKNOWN = 0; // 0x0
|
||||
field public static final int UPDATING = 2; // 0x2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package cyanogenmod.util {
|
||||
|
Loading…
Reference in New Issue
Block a user