Remove theme support

Change-Id: I41f1d0fa1ecc98c2872d2569534e6f2ef686a726
This commit is contained in:
Sam Mortimer
2017-09-09 00:42:35 -07:00
parent 6904e77152
commit 0912ee88c7
134 changed files with 1 additions and 6285 deletions

View File

@@ -100,13 +100,6 @@ public final class LineageContextConstants {
*/
public static final String LINEAGE_PERFORMANCE_SERVICE = "lineageperformance";
/**
* Controls changing and applying themes
*
* @hide
*/
public static final String LINEAGE_THEME_SERVICE = "lineagethemes";
/**
* Manages composed icons
*
@@ -190,14 +183,6 @@ public final class LineageContextConstants {
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
public static final String TELEPHONY = "org.lineageos.telephony";
/**
* Feature for {@link PackageManager#getSystemAvailableFeatures} and
* {@link PackageManager#hasSystemFeature}: The device includes the lineage theme service
* utilized by the lineage sdk.
*/
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
public static final String THEMES = "org.lineageos.theme";
/**
* Feature for {@link PackageManager#getSystemAvailableFeatures} and
* {@link PackageManager#hasSystemFeature}: The device includes the lineage performance service

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2015 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 lineageos.app;
/**
* The id value here matches the framework. Unknown is given a -1 value since future
* framework components will always be positive.
* @hide
*/
public enum ThemeComponent {
UNKNOWN(-1),
OVERLAY(0),
BOOT_ANIM(1),
WALLPAPER(2),
LOCKSCREEN(3),
FONT(4),
ICON(5),
SOUND(6);
public int id;
ThemeComponent(int id) {
this.id = id;
}
}

View File

@@ -1,206 +0,0 @@
/*
* Copyright (C) 2015 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 lineageos.app;
import android.os.Build;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @hide
*/
public class ThemeVersion {
private static final String THEME_VERSION_CLASS_NAME = "android.content.ThemeVersion";
private static final String THEME_VERSION_FIELD_NAME = "THEME_VERSION";
private static final String MIN_SUPPORTED_THEME_VERSION_FIELD_NAME =
"MIN_SUPPORTED_THEME_VERSION";
private static final int CM11 = 1;
private static final int CM12_PRE_VERSIONING = 2;
public static int getVersion() {
int version;
try {
Class<?> themeVersionClass = Class.forName(THEME_VERSION_CLASS_NAME);
Field themeVersionField = themeVersionClass.getField(THEME_VERSION_FIELD_NAME);
version = (Integer) themeVersionField.get(null);
} catch(Exception e) {
// Field doesn't exist. Fallback to SDK level
version = Build.VERSION.SDK_INT < 21 ? CM11 :
CM12_PRE_VERSIONING;
}
return version;
}
public static int getMinSupportedVersion() {
int getMinSupportedVersion;
try {
Class<?> themeVersionClass = Class.forName(THEME_VERSION_CLASS_NAME);
Field themeVersionField =
themeVersionClass.getField(MIN_SUPPORTED_THEME_VERSION_FIELD_NAME);
getMinSupportedVersion = (Integer) themeVersionField.get(null);
} catch(Exception e) {
// Field doesn't exist. Fallback to SDK level
getMinSupportedVersion = Build.VERSION.SDK_INT < 21 ? CM11 :
CM12_PRE_VERSIONING;
}
return getMinSupportedVersion;
}
public static ComponentVersion getComponentVersion(ThemeComponent component) {
int version = getVersion();
if (version == 1) {
throw new UnsupportedOperationException();
} else if (version == 2) {
return ThemeVersionImpl2.getDeviceComponentVersion(component);
} else {
return ThemeVersionImpl3.getDeviceComponentVersion(component);
}
}
public static List<ComponentVersion> getComponentVersions() {
int version = getVersion();
if (version == 1) {
throw new UnsupportedOperationException();
} else if (version == 2) {
return ThemeVersionImpl2.getDeviceComponentVersions();
} else {
return ThemeVersionImpl3.getDeviceComponentVersions();
}
}
public static class ComponentVersion {
protected int id;
protected String name;
protected ThemeComponent component;
protected int minVersion;
protected int currentVersion;
protected ComponentVersion(int id, ThemeComponent component, int targetVersion) {
this(id, component, component.name(), targetVersion, targetVersion);
}
protected ComponentVersion(int id,
ThemeComponent component,
String name,
int minVersion,
int targetVersion) {
this.id = id;
this.component = component;
this.name = name;
this.minVersion = minVersion;
this.currentVersion = targetVersion;
}
public ComponentVersion(ComponentVersion copy) {
this(copy.id, copy.component, copy.name, copy.minVersion, copy.currentVersion);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public ThemeComponent getComponent() {
return component;
}
public int getMinVersion() {
return minVersion;
}
public int getCurrentVersion() {
return currentVersion;
}
}
private static class ThemeVersionImpl2 {
private static ArrayList<ComponentVersion> cVersions = new ArrayList<ComponentVersion>() {
{
add(new ComponentVersion(0, ThemeComponent.OVERLAY, 2));
add(new ComponentVersion(1, ThemeComponent.BOOT_ANIM, 1));
add(new ComponentVersion(2, ThemeComponent.WALLPAPER, 1));
add(new ComponentVersion(3, ThemeComponent.LOCKSCREEN, 1));
add(new ComponentVersion(4, ThemeComponent.ICON, 1));
add(new ComponentVersion(5, ThemeComponent.FONT, 1));
add(new ComponentVersion(6, ThemeComponent.SOUND, 1));
}
};
public static ComponentVersion getDeviceComponentVersion(ThemeComponent component) {
for(ComponentVersion compVersion : cVersions) {
if (compVersion.component.equals(component)) {
return new ComponentVersion(compVersion);
}
}
return null;
}
public static List<ComponentVersion> getDeviceComponentVersions() {
ArrayList<ComponentVersion> versions = new ArrayList<ComponentVersion>();
versions.addAll(cVersions);
return versions;
}
}
private static class ThemeVersionImpl3 {
public static ComponentVersion getDeviceComponentVersion(ThemeComponent component) {
for(android.content.ThemeVersion.ComponentVersion version :
android.content.ThemeVersion.ComponentVersion.values()) {
ComponentVersion sdkVersionInfo = fwCompVersionToSdkVersion(version);
if (sdkVersionInfo.component.equals(component)) {
return sdkVersionInfo;
}
}
return null;
}
public static List<ComponentVersion> getDeviceComponentVersions() {
List<ComponentVersion> versions = new ArrayList<ComponentVersion>();
for(android.content.ThemeVersion.ComponentVersion version :
android.content.ThemeVersion.ComponentVersion.values()) {
versions.add(fwCompVersionToSdkVersion(version));
}
return versions;
}
public static ComponentVersion fwCompVersionToSdkVersion(
android.content.ThemeVersion.ComponentVersion version) {
// Find the SDK component with the matching id
// If no ID matches then the FW must have a newer component that we don't
// know anything about. We can still return the id and name
ThemeComponent component = ThemeComponent.UNKNOWN;
for(ThemeComponent aComponent : ThemeComponent.values()) {
if (aComponent.id == version.id) {
component = aComponent;
}
}
int id = version.id;
String name = version.name();
int minVersion = version.minSupportedVersion;
int targetVersion = version.currentVersion;
return new ComponentVersion(id, component, name, minVersion, targetVersion);
}
}
}

View File

@@ -95,45 +95,6 @@ public class Intent {
*/
public static final String ACTION_APP_FAILURE = "lineageos.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 =
"lineageos.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.lineageos.platform.internal.ThemeManagerService}
* Requires the {@link lineageos.platform.Manifest.permission#READ_THEMES} permission to
* receive this broadcast.
*/
public static final String ACTION_THEME_INSTALLED =
"lineageos.intent.action.THEME_INSTALLED";
/**
* Action sent from the provider when a theme has been updated.
* Requires the {@link lineageos.platform.Manifest.permission#READ_THEMES} permission to
* receive this broadcast.
*/
public static final String ACTION_THEME_UPDATED =
"lineageos.intent.action.THEME_UPDATED";
/**
* Action sent from the provider when a theme has been removed.
* Requires the {@link lineageos.platform.Manifest.permission#READ_THEMES} permission to
* receive this broadcast.
*/
public static final String ACTION_THEME_REMOVED =
"lineageos.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";
/**
* Implicit action to open live lock screen settings.
* @hide

View File

@@ -2601,24 +2601,6 @@ public final class LineageSettings {
*/
public static final String BUTTON_BRIGHTNESS = "button_brightness";
/**
* A '|' delimited list of theme components to apply from the default theme on first boot.
* Components can be one or more of the "mods_XXXXXXX" found in
* {@link ThemesContract$ThemesColumns}. Leaving this field blank assumes all components
* will be applied.
*
* ex: mods_icons|mods_overlays|mods_homescreen
*
* @hide
*/
public static final String DEFAULT_THEME_COMPONENTS = "default_theme_components";
/**
* Default theme to use. If empty, use holo.
* @hide
*/
public static final String DEFAULT_THEME_PACKAGE = "default_theme_package";
/**
* Developer options - Navigation Bar show switch
* @deprecated
@@ -2807,17 +2789,6 @@ public final class LineageSettings {
*/
public static final String ADVANCED_REBOOT = "advanced_reboot";
/**
* This will be set to the system's current theme API version when ThemeService starts.
* It is useful for when an upgrade from one version of Lineage to another occurs.
* For example, after a user upgrades from CM11 to CM12, the value of this field
* might be 19. ThemeService would then change the value to 21. This is useful
* when an API change breaks a theme. Themeservice can identify old themes and
* unapply them from the system.
* @hide
*/
public static final String THEME_PREV_BOOT_API_LEVEL = "theme_prev_boot_api_level";
/**
* Whether detail view for the location tile is enabled
* @hide
@@ -2950,8 +2921,6 @@ public final class LineageSettings {
LineageSettings.Secure.ADVANCED_MODE,
LineageSettings.Secure.BUTTON_BACKLIGHT_TIMEOUT,
LineageSettings.Secure.BUTTON_BRIGHTNESS,
LineageSettings.Secure.DEFAULT_THEME_COMPONENTS,
LineageSettings.Secure.DEFAULT_THEME_PACKAGE,
LineageSettings.Secure.DEV_FORCE_SHOW_NAVBAR,
LineageSettings.Secure.KEYBOARD_BRIGHTNESS,
LineageSettings.Secure.POWER_MENU_ACTIONS,
@@ -2970,7 +2939,6 @@ public final class LineageSettings {
LineageSettings.Secure.PROTECTED_COMPONENTS,
LineageSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
LineageSettings.Secure.ADVANCED_REBOOT,
LineageSettings.Secure.THEME_PREV_BOOT_API_LEVEL,
LineageSettings.Secure.LOCKSCREEN_TARGETS,
LineageSettings.Secure.RING_HOME_BUTTON_BEHAVIOR,
LineageSettings.Secure.PRIVACY_GUARD_DEFAULT,

View File

@@ -1,810 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package lineageos.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 = "org.lineageos.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_ALARM)) {
throw new IllegalArgumentException(
"Alarm 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,
};
}
public static class ThemeMixColumns {
/**
* Uri for accessing theme mixes
*/
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "theme_mixes");
/**
* Uri for retrieving the previews for the a theme mix.
* Querying the themes provider using this URI will return a cursor with a single row
* containing all the previews for the components associated with the given theme mix.
*/
public static final Uri PREVIEWS_URI = Uri.withAppendedPath(AUTHORITY_URI,
"theme_mix_previews");
/**
* The unique ID for a row.
* <P>Type: INTEGER (long)</P>
*/
public static final String _ID = "_id";
/**
* The name of this mix.
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
}
public static class ThemeMixEntryColumns {
/**
* Uri for accessing theme mix entries.
* These are the individual components associated with the saved theme mixes.
*/
public static final Uri CONTENT_URI =
Uri.withAppendedPath(AUTHORITY_URI, "theme_mix_entries");
/**
* The unique ID for a row.
* <P>Type: INTEGER (long)</P>
*/
public static final String _ID = "_id";
/**
* The unique ID of the theme mix this entry is for
* <P>Type: INTEGER (long)</P>
*/
public static final String THEME_MIX_ID = "theme_mix_id";
/**
* The component type this entry is associated with
* <P>Type: TEXT</P>
* <P>Valid types are:
* {@link ThemesColumns#MODIFIES_ALARMS}
* {@link ThemesColumns#MODIFIES_BOOT_ANIM}
* {@link ThemesColumns#MODIFIES_FONTS}
* {@link ThemesColumns#MODIFIES_ICONS}
* {@link ThemesColumns#MODIFIES_LAUNCHER}</P>
* {@link ThemesColumns#MODIFIES_LIVE_LOCK_SCREEN}
* {@link ThemesColumns#MODIFIES_LOCKSCREEN}
* {@link ThemesColumns#MODIFIES_NAVIGATION_BAR}
* {@link ThemesColumns#MODIFIES_NOTIFICATIONS}
* {@link ThemesColumns#MODIFIES_OVERLAYS}
* {@link ThemesColumns#MODIFIES_RINGTONES}
* {@link ThemesColumns#MODIFIES_STATUS_BAR}
*/
public static final String COMPONENT_TYPE = "component_type";
/*
* 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 COMPONENT_ID = "component_id";
/**
* Unique text to identify the theme package associated with this entry.
* <P>Type: TEXT</P>
*/
public static final String PACKAGE_NAME = "package_name";
/**
* The name of the theme associated with this entry.
* <P>Type: TEXT</P>
*/
public static final String THEME_NAME = "theme_name";
/**
* Whether the theme associated with this entry is currently installed.
* <P>Type: INTEGER (0|1)</P>
*/
public static final String IS_INSTALLED = "installed";
}
}

View File

@@ -1,23 +0,0 @@
/*
* 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 lineageos.themes;
/** {@hide} */
oneway interface IThemeChangeListener {
void onProgress(int progress);
void onFinish(boolean isSuccess);
}

View File

@@ -1,22 +0,0 @@
/*
* 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 lineageos.themes;
/** {@hide} */
oneway interface IThemeProcessingListener {
void onFinishedProcessing(String pkgName);
}

View File

@@ -1,44 +0,0 @@
/*
* 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 lineageos.themes;
import lineageos.themes.IThemeChangeListener;
import lineageos.themes.IThemeProcessingListener;
import lineageos.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();
}

View File

@@ -1,19 +0,0 @@
/*
* 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 lineageos.themes;
parcelable ThemeChangeRequest;

View File

@@ -1,324 +0,0 @@
/*
* 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 lineageos.themes;
//import android.content.pm.ThemeUtils;
import android.content.res.ThemeConfig;
import android.os.Parcel;
import android.os.Parcelable;
import lineageos.os.Concierge;
import lineageos.os.Concierge.ParcelInfo;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static lineageos.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 via the Concierge
ParcelInfo parcelInfo = Concierge.receiveParcel(source);
int parcelableVersion = parcelInfo.getParcelVersion();
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();
// Complete parcel info for the concierge
parcelInfo.complete();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// Tell the concierge to prepare the parcel
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
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);
// Complete the parcel info for the concierge
parcelInfo.complete();
}
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());
}
*/
}
}
}
}

View File

@@ -1,396 +0,0 @@
/*
* 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 lineageos.themes;
import android.content.Context;
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 lineageos.app.LineageContextConstants;
import lineageos.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(Context context) {
sService = getService();
if (context.getPackageManager().hasSystemFeature(
LineageContextConstants.Features.THEMES) && sService == null) {
Log.wtf(TAG, "Unable to get ThemeManagerService. The service either" +
" crashed, was not started, or the interface has been called to early in" +
" SystemServer init");
}
mHandler = new Handler(Looper.getMainLooper());
}
public static ThemeManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new ThemeManager(context);
}
return sInstance;
}
/** @hide */
public static IThemeService getService() {
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService(LineageContextConstants.LINEAGE_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
*/
@Deprecated
public void addClient(ThemeChangeListener listener) {
registerThemeChangeListener(listener);
}
/**
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
* instead
*/
@Deprecated
public void removeClient(ThemeChangeListener listener) {
unregisterThemeChangeListener(listener);
}
/**
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
* instead
*/
@Deprecated
public void onClientPaused(ThemeChangeListener listener) {
unregisterThemeChangeListener(listener);
}
/**
* @deprecated Use {@link ThemeManager#registerThemeChangeListener(ThemeChangeListener)} instead
*/
@Deprecated
public void onClientResumed(ThemeChangeListener listener) {
registerThemeChangeListener(listener);
}
/**
* @deprecated Use {@link ThemeManager#unregisterThemeChangeListener(ThemeChangeListener)}
* instead
*/
@Deprecated
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(ThemeProcessingListener 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);
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.internal.themes;
import android.graphics.Bitmap;
/** @hide */
interface IIconCacheManager {
boolean cacheComposedIcon(in Bitmap icon, String path);
}

View File

@@ -31,9 +31,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import lineageos.providers.ThemesContract.PreviewColumns;
import lineageos.providers.ThemesContract.ThemesColumns;
import libcore.io.IoUtils;
public class ImageUtils {
@@ -126,207 +123,4 @@ public class ImageUtils {
}
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;
}
}

View File

@@ -60,7 +60,6 @@ public class QSConstants {
public static final String DYNAMIC_TILE_SU = "su";
public static final String DYNAMIC_TILE_ADB = "adb";
public static final String DYNAMIC_TILE_LIVE_DISPLAY = "live_display";
public static final String DYNAMIC_TILE_THEMES = "themes";
protected static final ArrayList<String> STATIC_TILES_AVAILABLE = new ArrayList<String>();
protected static final ArrayList<String> DYNAMIC_TILES_AVAILBLE = new ArrayList<String>();
@@ -108,6 +107,5 @@ public class QSConstants {
DYNAMIC_TILES_AVAILBLE.add(DYNAMIC_TILE_NEXT_ALARM);
DYNAMIC_TILES_AVAILBLE.add(DYNAMIC_TILE_SU);
DYNAMIC_TILES_AVAILBLE.add(DYNAMIC_TILE_LIVE_DISPLAY);
DYNAMIC_TILES_AVAILBLE.add(DYNAMIC_TILE_THEMES);
}
}

View File

@@ -1,687 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.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 lineageos.providers.LineageSettings;
import lineageos.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.lineageos.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 = LineageSettings.Secure.getString(context.getContentResolver(),
LineageSettings.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();
}
}
}