sdk: introduce Style API
This API will allow apps to change global style mode and accent. Global style mode can be * Automatic (wallpaper) * Automatic (day of time) * Light * Dark Accent colors are defined in the caller application that will have to pass the package name. It's possible for apps to pass a Bitmap and get a suggestion of a global style + accent color that can be applied. Restrictions: * Only one accent can be enabled at time. * We're not limiting this to system apps, but we're marking this as dangerous permissions so apps will have to require it at runtime to the user. Change-Id: I921e8758c3ae093a88e897899612830258c97f8d Signed-off-by: Joey <joey@lineageos.org>
This commit is contained in:
@@ -25,7 +25,7 @@ LOCAL_PATH := $(call my-dir)
|
||||
lineage_platform_res := APPS/org.lineageos.platform-res_intermediates/src
|
||||
|
||||
# List of packages used in lineage-api-stubs
|
||||
lineage_stub_packages := lineageos.app:lineageos.content:lineageos.hardware:lineageos.media:lineageos.os:lineageos.preference:lineageos.profiles:lineageos.providers:lineageos.platform:lineageos.power:lineageos.util:lineageos.weather:lineageos.weatherservice
|
||||
lineage_stub_packages := lineageos.app:lineageos.content:lineageos.hardware:lineageos.media:lineageos.os:lineageos.preference:lineageos.profiles:lineageos.providers:lineageos.platform:lineageos.power:lineageos.util:lineageos.weather:lineageos.weatherservice:lineageos.style
|
||||
|
||||
# The LineageOS Platform Framework Library
|
||||
# ============================================================
|
||||
|
||||
@@ -270,6 +270,7 @@ package lineageos.hardware {
|
||||
method public boolean isAutomaticOutdoorModeEnabled();
|
||||
method public boolean isCABCEnabled();
|
||||
method public boolean isColorEnhancementEnabled();
|
||||
method public boolean isNightModeEnabled();
|
||||
method public boolean setAutoContrastEnabled(boolean);
|
||||
method public boolean setAutomaticOutdoorModeEnabled(boolean);
|
||||
method public boolean setCABCEnabled(boolean);
|
||||
@@ -279,7 +280,6 @@ package lineageos.hardware {
|
||||
method public boolean setMode(int);
|
||||
method public boolean setNightColorTemperature(int);
|
||||
method public boolean setPictureAdjustment(lineageos.hardware.HSIC);
|
||||
method public boolean isNightModeEnabled();
|
||||
field public static final int ADJUSTMENT_CONTRAST = 3; // 0x3
|
||||
field public static final int ADJUSTMENT_HUE = 0; // 0x0
|
||||
field public static final int ADJUSTMENT_INTENSITY = 2; // 0x2
|
||||
@@ -359,17 +359,14 @@ package lineageos.platform {
|
||||
ctor public Manifest.permission();
|
||||
field public static final java.lang.String ACCESS_WEATHER_MANAGER = "lineageos.permission.ACCESS_WEATHER_MANAGER";
|
||||
field public static final java.lang.String BIND_WEATHER_PROVIDER_SERVICE = "lineageos.permission.BIND_WEATHER_PROVIDER_SERVICE";
|
||||
field public static final java.lang.String CHANGE_STYLE = "lineageos.permission.CHANGE_STYLE";
|
||||
field public static final java.lang.String HARDWARE_ABSTRACTION_ACCESS = "lineageos.permission.HARDWARE_ABSTRACTION_ACCESS";
|
||||
field public static final java.lang.String MANAGE_LIVEDISPLAY = "lineageos.permission.MANAGE_LIVEDISPLAY";
|
||||
field public static final java.lang.String MANAGE_REMOTE_PREFERENCES = "lineageos.permission.MANAGE_REMOTE_PREFERENCES";
|
||||
field public static final java.lang.String MODIFY_MSIM_PHONE_STATE = "lineageos.permission.MODIFY_MSIM_PHONE_STATE";
|
||||
field public static final java.lang.String MODIFY_NETWORK_SETTINGS = "lineageos.permission.MODIFY_NETWORK_SETTINGS";
|
||||
field public static final java.lang.String MODIFY_PROFILES = "lineageos.permission.MODIFY_PROFILES";
|
||||
field public static final java.lang.String MODIFY_SOUND_SETTINGS = "lineageos.permission.MODIFY_SOUND_SETTINGS";
|
||||
field public static final java.lang.String PERFORMANCE_ACCESS = "lineageos.permission.PERFORMANCE_ACCESS";
|
||||
field public static final java.lang.String PROTECTED_APP = "lineageos.permission.PROTECTED_APP";
|
||||
field public static final java.lang.String READ_DATAUSAGE = "lineageos.permission.READ_DATAUSAGE";
|
||||
field public static final java.lang.String READ_MSIM_PHONE_STATE = "lineageos.permission.READ_MSIM_PHONE_STATE";
|
||||
field public static final java.lang.String READ_WEATHER = "lineageos.permission.READ_WEATHER";
|
||||
field public static final java.lang.String WRITE_DATAUSAGE = "lineageos.permission.WRITE_DATAUSAGE";
|
||||
field public static final java.lang.String WRITE_SECURE_SETTINGS = "lineageos.permission.WRITE_SECURE_SETTINGS";
|
||||
@@ -381,6 +378,10 @@ package lineageos.platform {
|
||||
ctor public R();
|
||||
}
|
||||
|
||||
public static final class R.anim {
|
||||
ctor public R.anim();
|
||||
}
|
||||
|
||||
public static final class R.array {
|
||||
ctor public R.array();
|
||||
}
|
||||
@@ -403,6 +404,10 @@ package lineageos.platform {
|
||||
ctor public R.bool();
|
||||
}
|
||||
|
||||
public static final class R.dimen {
|
||||
ctor public R.dimen();
|
||||
}
|
||||
|
||||
public static final class R.drawable {
|
||||
ctor public R.drawable();
|
||||
}
|
||||
@@ -796,6 +801,8 @@ package lineageos.providers {
|
||||
field public static final java.lang.String BATTERY_LIGHT_LOW_COLOR = "battery_light_low_color";
|
||||
field public static final java.lang.String BATTERY_LIGHT_MEDIUM_COLOR = "battery_light_medium_color";
|
||||
field public static final java.lang.String BATTERY_LIGHT_PULSE = "battery_light_pulse";
|
||||
field public static final java.lang.String BERRY_CURRENT_ACCENT = "berry_current_accent";
|
||||
field public static final java.lang.String BERRY_GLOBAL_STYLE = "berry_global_style";
|
||||
field public static final java.lang.String BLUETOOTH_ACCEPT_ALL_FILES = "bluetooth_accept_all_files";
|
||||
field public static final java.lang.String CALL_RECORDING_FORMAT = "call_recording_format";
|
||||
field public static final java.lang.String CAMERA_LAUNCH = "camera_launch";
|
||||
@@ -979,6 +986,31 @@ package lineageos.providers {
|
||||
|
||||
}
|
||||
|
||||
package lineageos.style {
|
||||
|
||||
public class StyleInterface {
|
||||
method public static lineageos.style.StyleInterface getInstance(android.content.Context);
|
||||
method public lineageos.style.Suggestion getSuggestion(android.graphics.Bitmap, int[]);
|
||||
method public boolean setAccent(java.lang.String);
|
||||
method public boolean setGlobalStyle(int);
|
||||
field public static final java.lang.String ACCENT_DEFAULT = "lineageos";
|
||||
field public static final java.lang.String CHANGE_STYLE_SETTINGS_PERMISSION = "lineageos.permission.CHANGE_STYLE";
|
||||
field public static final int STYLE_GLOBAL_AUTO_DAYTIME = 1; // 0x1
|
||||
field public static final int STYLE_GLOBAL_AUTO_WALLPAPER = 0; // 0x0
|
||||
field public static final int STYLE_GLOBAL_DARK = 3; // 0x3
|
||||
field public static final int STYLE_GLOBAL_LIGHT = 2; // 0x2
|
||||
}
|
||||
|
||||
public class Suggestion implements android.os.Parcelable {
|
||||
ctor public Suggestion(int, int);
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public final int globalStyle;
|
||||
field public final int selectedAccent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package lineageos.util {
|
||||
|
||||
public class ColorUtils {
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2018 The LineageOS 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.platform.internal;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.om.IOverlayManager;
|
||||
import android.content.om.OverlayInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import lineageos.app.LineageContextConstants;
|
||||
import lineageos.providers.LineageSettings;
|
||||
import lineageos.style.IStyleInterface;
|
||||
import lineageos.style.StyleInterface;
|
||||
import lineageos.style.Suggestion;
|
||||
import lineageos.util.palette.Palette;
|
||||
|
||||
/** @hide */
|
||||
public class StyleInterfaceService extends LineageSystemService {
|
||||
private static final String TAG = "LineageStyleInterfaceService";
|
||||
private static final String ACCENT_METADATA_COLOR = "lineage_berry_accent_preview";
|
||||
private static final int COLOR_DEFAULT = Color.BLACK;
|
||||
|
||||
private Context mContext;
|
||||
private IOverlayManager mOverlayService;
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
public StyleInterfaceService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
if (context.getPackageManager().hasSystemFeature(LineageContextConstants.Features.STYLES)) {
|
||||
publishBinderService(LineageContextConstants.LINEAGE_STYLE_INTERFACE, mService);
|
||||
} else {
|
||||
Log.wtf(TAG, "Lineage profile service started by system server but feature xml not" +
|
||||
" declared. Not publishing binder service!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureDeclaration() {
|
||||
return LineageContextConstants.Features.STYLES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
mOverlayService = IOverlayManager.Stub.asInterface(ServiceManager.getService("overlay"));
|
||||
}
|
||||
|
||||
private void enforceChangeStylePermission() {
|
||||
mContext.enforceCallingOrSelfPermission(StyleInterface.CHANGE_STYLE_SETTINGS_PERMISSION,
|
||||
"You do not have permissions to change system style");
|
||||
}
|
||||
|
||||
private boolean setGlobalStyleInternal(int mode) {
|
||||
return LineageSettings.System.putInt(mContext.getContentResolver(),
|
||||
LineageSettings.System.BERRY_GLOBAL_STYLE, mode);
|
||||
}
|
||||
|
||||
private boolean setAccentInternal(String pkgName) {
|
||||
if (!isChangeableOverlay(pkgName)) {
|
||||
Log.e(TAG, pkgName + ": is not a valid overlay package");
|
||||
return false;
|
||||
}
|
||||
|
||||
int userId = UserHandle.myUserId();
|
||||
|
||||
// Disable current accent
|
||||
String currentAccent = LineageSettings.System.getString(mContext.getContentResolver(),
|
||||
LineageSettings.System.BERRY_CURRENT_ACCENT);
|
||||
try {
|
||||
mOverlayService.setEnabled(currentAccent, false, userId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to disable current accent", e);
|
||||
}
|
||||
|
||||
if (StyleInterface.ACCENT_DEFAULT.equals(pkgName)) {
|
||||
return LineageSettings.System.putString(mContext.getContentResolver(),
|
||||
LineageSettings.System.BERRY_CURRENT_ACCENT, "");
|
||||
}
|
||||
|
||||
// Enable new one
|
||||
try {
|
||||
mOverlayService.setEnabled(pkgName, true, userId);
|
||||
return LineageSettings.System.putString(mContext.getContentResolver(),
|
||||
LineageSettings.System.BERRY_CURRENT_ACCENT, pkgName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to enable new accent", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Suggestion getSuggestionInternal(Bitmap source, int[] colors) {
|
||||
Palette palette = Palette.from(source).generate();
|
||||
|
||||
// Extract dominant color
|
||||
int sourceColor = palette.getVibrantColor(COLOR_DEFAULT);
|
||||
// If vibrant color extraction failed, let's try muted color
|
||||
if (sourceColor == COLOR_DEFAULT) {
|
||||
sourceColor = palette.getMutedColor(COLOR_DEFAULT);
|
||||
}
|
||||
|
||||
boolean isLight = Color.luminance(sourceColor) > 0.3;
|
||||
int bestColorPosition = getBestColor(sourceColor, colors);
|
||||
int suggestedGlobalStyle = isLight ?
|
||||
StyleInterface.STYLE_GLOBAL_LIGHT : StyleInterface.STYLE_GLOBAL_DARK;
|
||||
return new Suggestion(suggestedGlobalStyle, bestColorPosition);
|
||||
}
|
||||
|
||||
private int getBestColor(int sourceColor, int[] colors) {
|
||||
int best = 0;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
double diff = Math.sqrt(
|
||||
Math.pow(Color.red(colors[i]) - Color.red(sourceColor), 2) +
|
||||
Math.pow(Color.green(colors[i]) - Color.green(sourceColor), 2) +
|
||||
Math.pow(Color.blue(colors[i]) - Color.blue(sourceColor), 2));
|
||||
|
||||
if (diff < minDiff) {
|
||||
best = i;
|
||||
minDiff = diff;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
private boolean isChangeableOverlay(String pkgName) {
|
||||
if (pkgName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StyleInterface.ACCENT_DEFAULT.equals(pkgName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
PackageInfo pi = mPackageManager.getPackageInfo(pkgName, 0);
|
||||
return pi != null && !pi.isStaticOverlay && isValidAccent(pkgName);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidAccent(String pkgName) {
|
||||
try {
|
||||
ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName,
|
||||
PackageManager.GET_META_DATA);
|
||||
int color = ai.metaData == null ? -1 :
|
||||
ai.metaData.getInt(ACCENT_METADATA_COLOR, -1);
|
||||
return color != -1;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mService = new IStyleInterface.Stub() {
|
||||
@Override
|
||||
public boolean setGlobalStyle(int style) {
|
||||
enforceChangeStylePermission();
|
||||
/*
|
||||
* We need to clear the caller's identity in order to
|
||||
* allow this method call to modify settings
|
||||
* not allowed by the caller's permissions.
|
||||
*/
|
||||
long token = clearCallingIdentity();
|
||||
boolean success = setGlobalStyleInternal(style);
|
||||
restoreCallingIdentity(token);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAccent(String pkgName) {
|
||||
enforceChangeStylePermission();
|
||||
/*
|
||||
* We need to clear the caller's identity in order to
|
||||
* allow this method call to modify settings
|
||||
* not allowed by the caller's permissions.
|
||||
*/
|
||||
long token = clearCallingIdentity();
|
||||
boolean success = setAccentInternal(pkgName);
|
||||
restoreCallingIdentity(token);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Suggestion getSuggestion(Bitmap source, int[] colors) {
|
||||
enforceChangeStylePermission();
|
||||
/*
|
||||
* We need to clear the caller's identity in order to
|
||||
* allow this method call to modify settings
|
||||
* not allowed by the caller's permissions.
|
||||
*/
|
||||
long token = clearCallingIdentity();
|
||||
Suggestion result = getSuggestionInternal(source, colors);
|
||||
restoreCallingIdentity(token);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -117,6 +117,13 @@
|
||||
android:icon="@drawable/ic_launcher_lineageos"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<!-- Allows an application to change system style -->
|
||||
<permission android:name="lineageos.permission.CHANGE_STYLE"
|
||||
android:label="@string/permlab_changeStyle"
|
||||
android:description="@string/permdesc_changeStyle"
|
||||
android:icon="@drawable/ic_launcher_lineageos"
|
||||
android:protectionLevel="dangerous" />
|
||||
|
||||
<application android:process="system"
|
||||
android:persistent="true"
|
||||
android:hasCode="false"
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<item>org.lineageos.platform.internal.LineageWeatherManagerService</item>
|
||||
<item>org.lineageos.platform.internal.display.LiveDisplayService</item>
|
||||
<item>org.lineageos.platform.internal.LineageAudioService</item>
|
||||
<item>org.lineageos.platform.internal.StyleInterfaceService</item>
|
||||
</string-array>
|
||||
|
||||
<!-- The LineageSystemServer class that is invoked from Android's SystemServer -->
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
<string name="permlab_protectedApp">add and remove apps to protected apps</string>
|
||||
<string name="permdesc_protectedApp">Allows an app to mark other apps as protected and lock them.</string>
|
||||
|
||||
<!-- Labels for CHANGE_STYLE permission -->
|
||||
<string name="permlab_changeStyle">change system style</string>
|
||||
<string name="permdesc_changeStyle">Allows an app customize the system colors.</string>
|
||||
|
||||
<!-- Profiles -->
|
||||
<!-- Names of default profiles. -->
|
||||
<string name="profileNameDefault">Default</string>
|
||||
|
||||
@@ -96,6 +96,17 @@ public final class LineageContextConstants {
|
||||
*/
|
||||
public static final String LINEAGE_AUDIO_SERVICE = "lineageaudio";
|
||||
|
||||
/**
|
||||
* Use with {@link android.content.Context#getSystemService} to retrieve a
|
||||
* {@link lineageos.app.StyleInterface} interact with system style.
|
||||
*
|
||||
* @see android.content.Context#getSystemService
|
||||
* @see lineageos.app.StyleInterface
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String LINEAGE_STYLE_INTERFACE = "lineagestyle";
|
||||
|
||||
/**
|
||||
* Features supported by the Lineage SDK.
|
||||
*/
|
||||
@@ -147,5 +158,13 @@ public final class LineageContextConstants {
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
|
||||
public static final String AUDIO = "org.lineageos.audio";
|
||||
|
||||
/**
|
||||
* Feature for {@link PackageManager#getSystemAvailableFeatures} and
|
||||
* {@link PackageManager#hasSystemFeature}: The device includes the lineage style service
|
||||
* utilized by the lineage sdk.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
|
||||
public static final String STYLES = "org.lineageos.style";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +178,11 @@ public class Build {
|
||||
|
||||
/**
|
||||
* Unreleased preliminary version starting from LineageOS 15.1
|
||||
* <p>Applications targeting this or a later version will get access to these
|
||||
* new features!</p>
|
||||
* <ul>
|
||||
* <li>Change system colors via {@link lineageos.app.StyleInterface}
|
||||
* </ul>
|
||||
*/
|
||||
public static final int HACKBERRY = 8;
|
||||
}
|
||||
|
||||
28
sdk/src/java/lineageos/style/IStyleInterface.aidl
Normal file
28
sdk/src/java/lineageos/style/IStyleInterface.aidl
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2018 The LineageOS 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.style;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import lineageos.style.Suggestion;
|
||||
|
||||
/** {@hide} */
|
||||
interface IStyleInterface {
|
||||
boolean setGlobalStyle(int style);
|
||||
boolean setAccent(String pkgName);
|
||||
Suggestion getSuggestion(in Bitmap source, in int[] colors);
|
||||
}
|
||||
199
sdk/src/java/lineageos/style/StyleInterface.java
Normal file
199
sdk/src/java/lineageos/style/StyleInterface.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* 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.style;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import lineageos.app.LineageContextConstants;
|
||||
|
||||
public class StyleInterface {
|
||||
|
||||
/**
|
||||
* Global style: automatic (based on wallpaper) mode
|
||||
*
|
||||
* @see #setGlobalStyle
|
||||
*/
|
||||
public static final int STYLE_GLOBAL_AUTO_WALLPAPER = 0;
|
||||
|
||||
/**
|
||||
* Global style: automatic (based on day time) mode
|
||||
*
|
||||
* @see #setGlobalStyle
|
||||
*/
|
||||
public static final int STYLE_GLOBAL_AUTO_DAYTIME = 1;
|
||||
|
||||
/**
|
||||
* Global style: light
|
||||
*
|
||||
* @see #setGlobalStyle
|
||||
*/
|
||||
public static final int STYLE_GLOBAL_LIGHT = 2;
|
||||
|
||||
/**
|
||||
* Global style: dark
|
||||
*
|
||||
* @see #setGlobalStyle
|
||||
*/
|
||||
public static final int STYLE_GLOBAL_DARK = 3;
|
||||
|
||||
/**
|
||||
* Default accent
|
||||
* Used to remove any active accent and use default one
|
||||
*
|
||||
* @see #setAccent
|
||||
*/
|
||||
public static final String ACCENT_DEFAULT = "lineageos";
|
||||
|
||||
/**
|
||||
* Allows an application to change system style.
|
||||
* This is a dangerous permission, your app must request
|
||||
* it at runtime as any other dangerous permission
|
||||
*/
|
||||
public static final String CHANGE_STYLE_SETTINGS_PERMISSION =
|
||||
"lineageos.permission.CHANGE_STYLE";
|
||||
|
||||
private static final String TAG = "StyleInterface";
|
||||
|
||||
private static IStyleInterface sService;
|
||||
private static StyleInterface sInstance;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private StyleInterface(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
if (appContext != null) {
|
||||
mContext = appContext;
|
||||
} else {
|
||||
mContext = context;
|
||||
}
|
||||
sService = getService();
|
||||
if (context.getPackageManager().hasSystemFeature(
|
||||
LineageContextConstants.Features.STYLES) && sService == null) {
|
||||
throw new RuntimeException("Unable to get StyleInterfaceService. The service" +
|
||||
" either crashed, was not started, or the interface has been called to early" +
|
||||
" in SystemServer init");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create an instance of the {@link lineageos.app.StyleInterface}
|
||||
* @param context
|
||||
* @return {@link StyleInterface}
|
||||
*/
|
||||
public static StyleInterface getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new StyleInterface(context);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/** @hide **/
|
||||
public static IStyleInterface getService() {
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
}
|
||||
IBinder b = ServiceManager.getService(LineageContextConstants.LINEAGE_STYLE_INTERFACE);
|
||||
sService = IStyleInterface.Stub.asInterface(b);
|
||||
|
||||
if (b != null) {
|
||||
sService = IStyleInterface.Stub.asInterface(b);
|
||||
return sService;
|
||||
} else {
|
||||
Log.e(TAG, "null service. SAD!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global style.
|
||||
*
|
||||
* You will need {@link #CHANGE_STYLE_SETTINGS_PERMISSION}
|
||||
* to utilize this functionality.
|
||||
*
|
||||
* @see #STYLE_GLOBAL_AUTO_WALLPAPER
|
||||
* @see #STYLE_GLOBAL_AUTO_DAYTIME
|
||||
* @see #STYLE_GLOBAL_LIGHT
|
||||
* @see #STYLE_GLOBAL_DARK
|
||||
* @param style The style mode to set the device to.
|
||||
* One of {@link #STYLE_GLOBAL_AUTO_WALLPAPER},
|
||||
* {@link #STYLE_GLOBAL_AUTO_DAYTIME},
|
||||
* {@link #STYLE_GLOBAL_LIGHT} or
|
||||
* {@link #STYLE_GLOBAL_DARK}
|
||||
*/
|
||||
public boolean setGlobalStyle(int style) {
|
||||
if (sService == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.setGlobalStyle(style);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set color accent package.
|
||||
*
|
||||
* You will need {@link #CHANGE_STYLE_SETTINGS_PERMISSION}
|
||||
* to utilize this functionality.
|
||||
*
|
||||
* @param pkgName The package name of the accent
|
||||
*/
|
||||
public boolean setAccent(String pkgName) {
|
||||
if (sService == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.setAccent(pkgName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best color that suites a bitmap object and the appropriate global style
|
||||
*
|
||||
* @param source The object you want the suggested color to be matched with
|
||||
* @param colors A list of colors that the selection will be made from
|
||||
*
|
||||
* @return suggestion for global style + accent combination
|
||||
*/
|
||||
public Suggestion getSuggestion(Bitmap source, int[] colors) {
|
||||
if (colors.length == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"The colors array argument must contain at least one element");
|
||||
}
|
||||
Suggestion fallback = new Suggestion(STYLE_GLOBAL_LIGHT, colors[0]);
|
||||
|
||||
if (sService == null) {
|
||||
return fallback;
|
||||
}
|
||||
try {
|
||||
return sService.getSuggestion(source, colors);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
20
sdk/src/java/lineageos/style/Suggestion.aidl
Normal file
20
sdk/src/java/lineageos/style/Suggestion.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2018 The LineageOS 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.style;
|
||||
|
||||
parcelable Suggestion;
|
||||
94
sdk/src/java/lineageos/style/Suggestion.java
Normal file
94
sdk/src/java/lineageos/style/Suggestion.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2018 The LineageOS 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.style;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import lineageos.os.Build;
|
||||
import lineageos.os.Concierge;
|
||||
import lineageos.os.Concierge.ParcelInfo;
|
||||
|
||||
public class Suggestion implements Parcelable {
|
||||
public final int globalStyle;
|
||||
public final int selectedAccent;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @see lineageos.style.StyleInterface#getSuggestion
|
||||
*
|
||||
* @param globalStyle one of {@link #STYLE_GLOBAL_LIGHT} or {@link #STYLE_GLOBAL_DARK}
|
||||
* @param colorPosition position of selected color in the input array
|
||||
*/
|
||||
public Suggestion(int globalStyle, int selectedAccent) {
|
||||
this.globalStyle = globalStyle;
|
||||
this.selectedAccent = selectedAccent;
|
||||
}
|
||||
|
||||
private Suggestion(Parcel parcel) {
|
||||
ParcelInfo parcelInfo = Concierge.receiveParcel(parcel);
|
||||
int parcelableVersion = parcelInfo.getParcelVersion();
|
||||
|
||||
if (parcelableVersion >= Build.LINEAGE_VERSION_CODES.HACKBERRY) {
|
||||
globalStyle = parcel.readInt();
|
||||
selectedAccent = parcel.readInt();
|
||||
} else {
|
||||
globalStyle = 0;
|
||||
selectedAccent = 0;
|
||||
}
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final Parcelable.Creator<Suggestion> CREATOR =
|
||||
new Parcelable.Creator<Suggestion>() {
|
||||
|
||||
@Override
|
||||
public Suggestion createFromParcel(Parcel source) {
|
||||
return new Suggestion(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Suggestion[] newArray(int size) {
|
||||
return new Suggestion[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Tell the concierge to prepare the parcel
|
||||
ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
|
||||
|
||||
// ==== HACKBERRY ====
|
||||
dest.writeInt(globalStyle);
|
||||
dest.writeInt(selectedAccent);
|
||||
|
||||
// Complete parcel info for the concierge
|
||||
parcelInfo.complete();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user