LLS: Add live lock screen service [1/4]
The live lock screen service is resposonsible for deciding what LLS should be displayed at any given time. Live lock screens can be swapped out using a priority based system. Change-Id: Ifba73e839b749fe78a9e4ee347dd20eea6bf0a22
This commit is contained in:
parent
11334c9592
commit
bfa500dd15
@ -196,6 +196,38 @@ package cyanogenmod.app {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "cyanogenmod.app.CustomTileListenerService";
|
||||
}
|
||||
|
||||
public class LiveLockScreenInfo implements android.os.Parcelable {
|
||||
ctor public LiveLockScreenInfo(android.content.ComponentName, int);
|
||||
ctor public LiveLockScreenInfo();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo clone();
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<cyanogenmod.app.LiveLockScreenInfo> CREATOR;
|
||||
field public static final int PRIORITY_DEFAULT = 0; // 0x0
|
||||
field public static final int PRIORITY_HIGH = 1; // 0x1
|
||||
field public static final int PRIORITY_LOW = -1; // 0xffffffff
|
||||
field public static final int PRIORITY_MAX = 2; // 0x2
|
||||
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
|
||||
field public android.content.ComponentName component;
|
||||
field public int priority;
|
||||
}
|
||||
|
||||
public static class LiveLockScreenInfo.Builder {
|
||||
ctor public LiveLockScreenInfo.Builder();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo build();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo.Builder setComponent(android.content.ComponentName);
|
||||
method public cyanogenmod.app.LiveLockScreenInfo.Builder setPriority(int);
|
||||
}
|
||||
|
||||
public class LiveLockScreenManager {
|
||||
method public void cancel(int);
|
||||
method public cyanogenmod.app.LiveLockScreenInfo getDefaultLiveLockScreen();
|
||||
method public static cyanogenmod.app.LiveLockScreenManager getInstance(android.content.Context);
|
||||
method public void setDefaultLiveLockScreen(cyanogenmod.app.LiveLockScreenInfo);
|
||||
method public boolean show(int, cyanogenmod.app.LiveLockScreenInfo);
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "cyanogenmod.app.LiveLockScreenManagerService";
|
||||
}
|
||||
|
||||
public class PartnerInterface {
|
||||
method public java.lang.String getCurrentHotwordPackageName();
|
||||
method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context);
|
||||
@ -564,6 +596,7 @@ package cyanogenmod.platform {
|
||||
field public static final java.lang.String ACCESS_APP_SUGGESTIONS = "cyanogenmod.permission.ACCESS_APP_SUGGESTIONS";
|
||||
field public static final java.lang.String ACCESS_THEME_MANAGER = "cyanogenmod.permission.ACCESS_THEME_MANAGER";
|
||||
field public static final java.lang.String HARDWARE_ABSTRACTION_ACCESS = "cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_MANAGER_ACCESS = "cyanogenmod.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS";
|
||||
field public static final java.lang.String MANAGE_ALARMS = "cyanogenmod.permission.MANAGE_ALARMS";
|
||||
field public static final java.lang.String MANAGE_PERSISTENT_STORAGE = "cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE";
|
||||
field public static final java.lang.String MODIFY_MSIM_PHONE_STATE = "cyanogenmod.permission.MODIFY_MSIM_PHONE_STATE";
|
||||
|
@ -0,0 +1,415 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.cyanogenmod.platform.internal;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
import cyanogenmod.app.ILiveLockScreenChangeListener;
|
||||
import cyanogenmod.app.ILiveLockScreenManager;
|
||||
import cyanogenmod.app.ILiveLockScreenManagerProvider;
|
||||
import cyanogenmod.app.LiveLockScreenInfo;
|
||||
import cyanogenmod.app.LiveLockScreenManager;
|
||||
import cyanogenmod.platform.Manifest;
|
||||
import cyanogenmod.providers.CMSettings;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Live lock screen service broker for connecting clients to a backing Live lock screen manager
|
||||
* service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class LiveLockScreenServiceBroker extends SystemService {
|
||||
private static final String TAG = LiveLockScreenServiceBroker.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MSG_TRY_CONNECTING = 1;
|
||||
|
||||
private static final long SERVICE_CONNECTION_WAIT_TIME_MS = 4 * 1000L; // 4 seconds
|
||||
|
||||
private Context mContext;
|
||||
// The actual LLS service to invoke
|
||||
private ILiveLockScreenManagerProvider mService;
|
||||
|
||||
// Cached change listeners
|
||||
private final RemoteCallbackList<ILiveLockScreenChangeListener> mChangeListeners =
|
||||
new RemoteCallbackList<>();
|
||||
|
||||
private LiveLockScreenInfo mDefaultLlsInfo;
|
||||
|
||||
private final Handler mConnectionHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_TRY_CONNECTING:
|
||||
tryConnecting();
|
||||
break;
|
||||
default:
|
||||
Slog.e(TAG, "Unknown message");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Slog.i(TAG, "LiveLockScreenManagerService connected");
|
||||
synchronized (LiveLockScreenServiceBroker.this) {
|
||||
mService = ILiveLockScreenManagerProvider.Stub.asInterface(service);
|
||||
LiveLockScreenServiceBroker.this.notifyAll();
|
||||
// If any change listeners are cached, register them with the newly connected
|
||||
// service.
|
||||
int N = mChangeListeners.getRegisteredCallbackCount();
|
||||
if (mService != null && N > 0) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
try {
|
||||
mService.registerChangeListener(mChangeListeners.getBroadcastItem(i));
|
||||
} catch (RemoteException e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Slog.i(TAG, "LiveLockScreenManagerService unexpectedly disconnected");
|
||||
synchronized (LiveLockScreenServiceBroker.this) {
|
||||
mService = null;
|
||||
LiveLockScreenServiceBroker.this.notifyAll();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ILiveLockScreenManager implementation to use when no backing service can be found.
|
||||
*/
|
||||
private final ILiveLockScreenManagerProvider mServiceStubForFailure =
|
||||
new ILiveLockScreenManagerProvider() {
|
||||
@Override
|
||||
public void enqueueLiveLockScreen(String pkg, int id, LiveLockScreenInfo lls,
|
||||
int[] idReceived, int userid) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelLiveLockScreen(String pkg, int id, int userId) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo getCurrentLiveLockScreen() throws RemoteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultLiveLockScreen(LiveLockScreenInfo llsInfo) throws RemoteException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLiveLockScreenEnabled() throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final class BinderService extends ILiveLockScreenManager.Stub {
|
||||
|
||||
@Override
|
||||
public void enqueueLiveLockScreen(String pkg, int id,
|
||||
LiveLockScreenInfo lls, int[] idReceived, int userId) throws RemoteException {
|
||||
getServiceGuarded().enqueueLiveLockScreen(pkg, id, lls, idReceived, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelLiveLockScreen(String pkg, int id, int userId) throws RemoteException {
|
||||
getServiceGuarded().cancelLiveLockScreen(pkg, id, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo getCurrentLiveLockScreen() throws RemoteException {
|
||||
return getServiceGuarded().getCurrentLiveLockScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo getDefaultLiveLockScreen() throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
return getDefaultLiveLockScreenInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultLiveLockScreen(LiveLockScreenInfo llsInfo) throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
setDefaultLiveLockScreenInternal(llsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLiveLockScreenEnabled(boolean enabled) throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
setLiveLockScreenEnabledInternal(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLiveLockScreenEnabled() throws RemoteException {
|
||||
return getServiceGuarded().getLiveLockScreenEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
boolean registered = getServiceGuarded().registerChangeListener(listener);
|
||||
if (registered) {
|
||||
mChangeListeners.register(listener);
|
||||
}
|
||||
return getServiceGuarded().registerChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
boolean unregistered = getServiceGuarded().unregisterChangeListener(listener);
|
||||
if (unregistered) {
|
||||
mChangeListeners.unregister(listener);
|
||||
}
|
||||
return unregistered;
|
||||
}
|
||||
}
|
||||
|
||||
public LiveLockScreenServiceBroker(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (DEBUG) Slog.d(TAG, "service started");
|
||||
if (mContext.getPackageManager().hasSystemFeature(
|
||||
CMContextConstants.Features.LIVE_LOCK_SCREEN)) {
|
||||
publishBinderService(CMContextConstants.CM_LIVE_LOCK_SCREEN_SERVICE,
|
||||
new BinderService());
|
||||
} else {
|
||||
Slog.wtf(TAG, "CM live lock screen service started by system server but feature xml " +
|
||||
"not declared. Not publishing binder service!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||
if (DEBUG) Slog.d(TAG, "Third party apps ready");
|
||||
|
||||
// Initialize the default LLS component
|
||||
String defComponent = CMSettings.Secure.getString(mContext.getContentResolver(),
|
||||
CMSettings.Secure.DEFAULT_LIVE_LOCK_SCREEN_COMPONENT);
|
||||
if (defComponent != null) {
|
||||
mDefaultLlsInfo = new LiveLockScreenInfo.Builder()
|
||||
.setComponent(ComponentName.unflattenFromString(defComponent))
|
||||
.build();
|
||||
}
|
||||
// Now that 3rd party apps are ready, try connecting to the backing service
|
||||
tryConnecting();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds to the backing service if one is found
|
||||
*/
|
||||
private void tryConnecting() {
|
||||
Slog.i(TAG, "Connecting to LiveLockScreenManagerService");
|
||||
synchronized (this) {
|
||||
if (mService != null) {
|
||||
Slog.d(TAG, "Already connected");
|
||||
return;
|
||||
}
|
||||
final Intent intent = new Intent();
|
||||
final ComponentName cn = getLiveLockScreenServiceComponent();
|
||||
if (cn == null) {
|
||||
Slog.e(TAG, "No live lock screen manager service found");
|
||||
return;
|
||||
}
|
||||
intent.setComponent(getLiveLockScreenServiceComponent());
|
||||
try {
|
||||
if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
|
||||
Slog.e(TAG, "Failed to bind to LiveLockScreenManagerService");
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "Forbidden to bind to LiveLockScreenManagerService", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries package manager for the component which handles the
|
||||
* {@link LiveLockScreenManager#SERVICE_INTERFACE} and has been granted the
|
||||
* {@link org.cyanogenmod.platform.internal.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_PROVIDER}
|
||||
* permission.
|
||||
*
|
||||
* @return A valid component that supports {@link LiveLockScreenManager#SERVICE_INTERFACE} or
|
||||
* null if no component can be found.
|
||||
*/
|
||||
@Nullable private ComponentName getLiveLockScreenServiceComponent() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
Intent intent = new Intent(LiveLockScreenManager.SERVICE_INTERFACE);
|
||||
List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, 0);
|
||||
for (ResolveInfo info : resolveInfos) {
|
||||
if (info != null) {
|
||||
if (pm.checkPermission(Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_PROVIDER,
|
||||
info.serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED &&
|
||||
info.serviceInfo.isEnabled()) {
|
||||
return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ILiveLockScreenManagerProvider getOrConnectService() {
|
||||
synchronized (this) {
|
||||
if (mService != null) {
|
||||
return mService;
|
||||
}
|
||||
// Service is not connected. Try blocking connecting.
|
||||
Slog.w(TAG, "LiveLockScreenManagerService not connected. Try connecting...");
|
||||
mConnectionHandler.sendMessage(
|
||||
mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
|
||||
final long shouldEnd =
|
||||
SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
|
||||
long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
|
||||
while (waitTime > 0) {
|
||||
try {
|
||||
// TODO: consider using Java concurrent construct instead of raw object wait
|
||||
this.wait(waitTime);
|
||||
} catch (InterruptedException e) {
|
||||
Slog.w(TAG, "Connection wait interrupted", e);
|
||||
}
|
||||
if (mService != null) {
|
||||
// Success
|
||||
return mService;
|
||||
}
|
||||
// Calculate remaining waiting time to make sure we wait the full timeout period
|
||||
waitTime = shouldEnd - SystemClock.elapsedRealtime();
|
||||
}
|
||||
// Timed out. Something's really wrong.
|
||||
Slog.e(TAG, "Can not connect to LiveLockScreenManagerService (timed out)");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure to return a non-empty service instance. Return the connected LiveLockScreenManager
|
||||
* instance, if not connected, try connecting. If fail to connect, return a fake service
|
||||
* instance which returns failure to service caller.
|
||||
*
|
||||
* @return a non-empty service instance, real or fake
|
||||
*/
|
||||
private ILiveLockScreenManagerProvider getServiceGuarded() {
|
||||
final ILiveLockScreenManagerProvider service = getOrConnectService();
|
||||
if (service != null) {
|
||||
return service;
|
||||
}
|
||||
return mServiceStubForFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the
|
||||
* {@link cyanogenmod.platform.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE}
|
||||
* permission.
|
||||
*/
|
||||
private void enforcePrivateAccessPermission() {
|
||||
mContext.enforceCallingPermission(
|
||||
Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE, null);
|
||||
}
|
||||
|
||||
private LiveLockScreenInfo getDefaultLiveLockScreenInternal() {
|
||||
return mDefaultLlsInfo;
|
||||
}
|
||||
|
||||
private void setDefaultLiveLockScreenInternal(LiveLockScreenInfo llsInfo) {
|
||||
if (llsInfo != null && llsInfo.component != null) {
|
||||
// Check that the package this component belongs to has the third party keyguard perm
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final boolean hasThirdPartyKeyguardPermission = pm.checkPermission(
|
||||
Manifest.permission.THIRD_PARTY_KEYGUARD,
|
||||
llsInfo.component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
|
||||
if (!hasThirdPartyKeyguardPermission) {
|
||||
Slog.e(TAG, "Package " + llsInfo.component.getPackageName() +
|
||||
" does not have " + Manifest.permission.THIRD_PARTY_KEYGUARD);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
CMSettings.Secure.putString(mContext.getContentResolver(),
|
||||
CMSettings.Secure.DEFAULT_LIVE_LOCK_SCREEN_COMPONENT,
|
||||
(llsInfo != null && llsInfo.component != null)
|
||||
? llsInfo.component.flattenToString()
|
||||
: "");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
mDefaultLlsInfo = llsInfo;
|
||||
try {
|
||||
mService.updateDefaultLiveLockScreen(llsInfo);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
private void setLiveLockScreenEnabledInternal(boolean enabled) {
|
||||
long token = Binder.clearCallingIdentity();
|
||||
CMSettings.Secure.putInt(mContext.getContentResolver(),
|
||||
CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED, enabled ? 1 : 0);
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
@ -172,6 +172,26 @@
|
||||
android:description="@string/permdesc_perfAccessDesc"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows an application to access the live lock screen manager. -->
|
||||
<permission android:name="cyanogenmod.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS"
|
||||
android:label="@string/permlab_accessLiveLockScreenService"
|
||||
android:description="@string/permdesc_accessLiveLockScreenService"
|
||||
android:protectionLevel="dangerous" />
|
||||
|
||||
<!-- Allows system apps privileged access to the live lock screen manager.
|
||||
@hide -->
|
||||
<permission android:name="cyanogenmod.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE"
|
||||
android:label="@string/permlab_accessLiveLockScreenServicePrivate"
|
||||
android:description="@string/permdesc_accessLiveLockScreenServicePrivate"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Permission required to be held for a service that provides a LiveLockScreenManagerService
|
||||
@hide -->
|
||||
<permission android:name="cyanogenmod.permission.LIVE_LOCK_SCREEN_MANAGER_PROVIDER"
|
||||
android:label="@string/permlab_accessLiveLockScreenServiceProvider"
|
||||
android:description="@string/permdesc_accessLiveLockScreenServiceProvider"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<application android:process="system"
|
||||
android:persistent="true"
|
||||
android:hasCode="false"
|
||||
|
@ -89,5 +89,6 @@
|
||||
<item>org.cyanogenmod.platform.internal.PerformanceManagerService</item>
|
||||
<item>org.cyanogenmod.platform.internal.ThemeManagerService</item>
|
||||
<item>org.cyanogenmod.platform.internal.IconCacheManagerService</item>
|
||||
<item>org.cyanogenmod.platform.internal.LiveLockScreenServiceBroker</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@ -165,4 +165,19 @@
|
||||
<string name="permlab_perfAccess">access performance manager</string>
|
||||
<!-- Performance manager permission description -->
|
||||
<string name="permdesc_perfAccessDesc">Allows an app to access the performance service. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Access live lock screen manager service permission label -->
|
||||
<string name="permlab_accessLiveLockScreenService">access live lock screen manager service</string>
|
||||
<!-- Access live lock screen manager service permission description -->
|
||||
<string name="permdesc_accessLiveLockScreenService">Allows an app to access the live lock screen manager service.</string>
|
||||
<!-- Privileged access live lock screen manager service permission label -->
|
||||
<string name="permlab_accessLiveLockScreenServicePrivate">access live lock screen manager service</string>
|
||||
<!-- Privileged access live lock screen manager service permission description -->
|
||||
<string name="permdesc_accessLiveLockScreenServicePrivate">Allows system apps to access the live lock screen manager service.</string>
|
||||
<!-- Live lock screen manager service provider permission label -->
|
||||
<string name="permlab_accessLiveLockScreenServiceProvider">provide live lock screen manager service</string>
|
||||
<!-- Live lock screen manager service provider permission description -->
|
||||
<string name="permdesc_accessLiveLockScreenServiceProvider">Allows a service to provide the live lock screen manager service.</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
226
src/java/cyanogenmod/app/BaseLiveLockManagerService.java
Normal file
226
src/java/cyanogenmod/app/BaseLiveLockManagerService.java
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import cyanogenmod.platform.Manifest;
|
||||
|
||||
/**
|
||||
* Base Live lock screen manager service to be extended by applications that implement the
|
||||
* {@link LiveLockScreenManager#SERVICE_INTERFACE}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
abstract public class BaseLiveLockManagerService extends Service
|
||||
implements ILiveLockScreenManagerProvider {
|
||||
private static final String TAG = BaseLiveLockManagerService.class.getSimpleName();
|
||||
|
||||
private final RemoteCallbackList<ILiveLockScreenChangeListener> mChangeListeners =
|
||||
new RemoteCallbackList<>();
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return mService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder asBinder() {
|
||||
return mService;
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public void enqueueLiveLockScreen(String pkg, int id, LiveLockScreenInfo lls,
|
||||
int[] idReceived, int userId) throws RemoteException;
|
||||
|
||||
@Override
|
||||
abstract public void cancelLiveLockScreen(String pkg, int id, int userId)
|
||||
throws RemoteException;
|
||||
|
||||
@Override
|
||||
abstract public LiveLockScreenInfo getCurrentLiveLockScreen() throws RemoteException;
|
||||
|
||||
@Override
|
||||
abstract public void updateDefaultLiveLockScreen(LiveLockScreenInfo llsInfo)
|
||||
throws RemoteException;
|
||||
|
||||
@Override
|
||||
public boolean getLiveLockScreenEnabled() throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean registerChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
return mChangeListeners.register(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean unregisterChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
return mChangeListeners.unregister(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called whenever there is an update to the current Live lock screen
|
||||
* to be displayed.
|
||||
*
|
||||
* @param llsInfo LiveLockScreenInfo for the current Live lock screen
|
||||
*/
|
||||
protected final void notifyChangeListeners(LiveLockScreenInfo llsInfo) {
|
||||
int N = mChangeListeners.beginBroadcast();
|
||||
for (int i = 0; i < N; i++) {
|
||||
ILiveLockScreenChangeListener listener = mChangeListeners.getBroadcastItem(i);
|
||||
try {
|
||||
listener.onLiveLockScreenChanged(llsInfo);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Unable to notifiy change listener", e);
|
||||
}
|
||||
}
|
||||
mChangeListeners.finishBroadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caller has been granted the
|
||||
* {@link cyanogenmod.platform.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE}
|
||||
* permission.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private final boolean hasPrivatePermissions() {
|
||||
return checkCallingPermission(Manifest.permission
|
||||
.LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the {@link cyanogenmod.platform.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_ACCESS}
|
||||
* permission.
|
||||
*/
|
||||
protected final void enforceAccessPermission() {
|
||||
if (hasPrivatePermissions()) return;
|
||||
|
||||
enforceCallingPermission(Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the
|
||||
* {@link cyanogenmod.platform.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE}
|
||||
* permission.
|
||||
*/
|
||||
protected final void enforcePrivateAccessPermission() {
|
||||
enforceCallingPermission(
|
||||
Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the LLS being shown/canceled is from the calling package or from a system app that
|
||||
* has the
|
||||
* {@link cyanogenmod.platform.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_ACCESS_PRIVATE}
|
||||
* permission.
|
||||
*
|
||||
* @param pkg Package name of caller
|
||||
* @param llsInfo Live lock screen info with component to check
|
||||
*/
|
||||
protected final void enforceSamePackageOrSystem(String pkg,
|
||||
@NonNull LiveLockScreenInfo llsInfo) {
|
||||
// only apps with the private permission can show/cancel live lock screens from other
|
||||
// packages
|
||||
if (hasPrivatePermissions()) return;
|
||||
|
||||
if (llsInfo.component != null && !llsInfo.component.getPackageName().equals(pkg)) {
|
||||
throw new SecurityException("Modifying Live lock screen from different packages not " +
|
||||
"allowed. Calling package: " + pkg + " LLS package: " +
|
||||
llsInfo.component.getPackageName());
|
||||
}
|
||||
|
||||
final int uid = Binder.getCallingUid();
|
||||
try {
|
||||
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
|
||||
pkg, 0, UserHandle.getCallingUserId());
|
||||
if (ai == null) {
|
||||
throw new SecurityException("Unknown package " + pkg);
|
||||
}
|
||||
if (!UserHandle.isSameApp(ai.uid, uid)) {
|
||||
throw new SecurityException("Calling uid " + uid + " gave package"
|
||||
+ pkg + " which is owned by uid " + ai.uid);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
throw new SecurityException("Unknown package " + pkg + "\n" + re);
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mService = new ILiveLockScreenManagerProvider.Stub() {
|
||||
@Override
|
||||
public void enqueueLiveLockScreen(String pkg, int id, LiveLockScreenInfo llsInfo,
|
||||
int[] idReceived, int userId) throws RemoteException {
|
||||
enforceAccessPermission();
|
||||
enforceSamePackageOrSystem(pkg, llsInfo);
|
||||
BaseLiveLockManagerService.this.enqueueLiveLockScreen(pkg, id, llsInfo, idReceived,
|
||||
userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelLiveLockScreen(String pkg, int id, int userId) throws RemoteException {
|
||||
enforceAccessPermission();
|
||||
BaseLiveLockManagerService.this.cancelLiveLockScreen(pkg, id, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo getCurrentLiveLockScreen() throws RemoteException {
|
||||
enforceAccessPermission();
|
||||
return BaseLiveLockManagerService.this.getCurrentLiveLockScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultLiveLockScreen(LiveLockScreenInfo llsInfo) throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
BaseLiveLockManagerService.this.updateDefaultLiveLockScreen(llsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLiveLockScreenEnabled() throws RemoteException {
|
||||
enforceAccessPermission();
|
||||
return BaseLiveLockManagerService.this.getLiveLockScreenEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
return BaseLiveLockManagerService.this.registerChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterChangeListener(
|
||||
ILiveLockScreenChangeListener listener) throws RemoteException {
|
||||
enforcePrivateAccessPermission();
|
||||
return BaseLiveLockManagerService.this.unregisterChangeListener(listener);
|
||||
}
|
||||
};
|
||||
}
|
@ -114,6 +114,11 @@ public final class CMContextConstants {
|
||||
*/
|
||||
public static final String CM_ICON_CACHE_SERVICE = "cmiconcache";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final String CM_LIVE_LOCK_SCREEN_SERVICE = "cmlivelockscreen";
|
||||
|
||||
/**
|
||||
* Features supported by the CMSDK.
|
||||
*/
|
||||
@ -181,5 +186,13 @@ public final class CMContextConstants {
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
|
||||
public static final String PARTNER = "org.cyanogenmod.partner";
|
||||
|
||||
/*
|
||||
* Feature for {@link PackageManager#getSystemAvailableFeatures} and
|
||||
* {@link PackageManager#hasSystemFeature}: The device includes the Live lock screen
|
||||
* feature.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.FEATURE)
|
||||
public static final String LIVE_LOCK_SCREEN = "org.cyanogenmod.livelockscreen";
|
||||
}
|
||||
}
|
||||
|
27
src/java/cyanogenmod/app/ILiveLockScreenChangeListener.aidl
Normal file
27
src/java/cyanogenmod/app/ILiveLockScreenChangeListener.aidl
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
** Copyright (C) 2016 The CyanogenMod Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import cyanogenmod.app.LiveLockScreenInfo;
|
||||
|
||||
/**
|
||||
* Listener interface for notifying clients that the current Live lock screen has changed.
|
||||
* @hide
|
||||
*/
|
||||
interface ILiveLockScreenChangeListener {
|
||||
void onLiveLockScreenChanged(in LiveLockScreenInfo llsInfo);
|
||||
}
|
73
src/java/cyanogenmod/app/ILiveLockScreenManager.aidl
Normal file
73
src/java/cyanogenmod/app/ILiveLockScreenManager.aidl
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
** Copyright (C) 2016 The CyanogenMod Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import cyanogenmod.app.ILiveLockScreenChangeListener;
|
||||
import cyanogenmod.app.LiveLockScreenInfo;
|
||||
|
||||
/** @hide */
|
||||
interface ILiveLockScreenManager {
|
||||
|
||||
/**
|
||||
* Enqueue a Live lock screen to be displayed.
|
||||
*/
|
||||
void enqueueLiveLockScreen(String pkg, int id, in LiveLockScreenInfo lls,
|
||||
inout int[] idReceived, int userId);
|
||||
|
||||
/**
|
||||
* Cancel displaying a Live lock screen.
|
||||
*/
|
||||
void cancelLiveLockScreen(String pkg, int id, int userId);
|
||||
|
||||
/**
|
||||
* Get the current Live lock screen that should be displayed.
|
||||
*/
|
||||
LiveLockScreenInfo getCurrentLiveLockScreen();
|
||||
|
||||
/**
|
||||
* Get the default Live lock screen. This is the Live lock screen that should be displayed
|
||||
* when no other Live lock screens are queued.
|
||||
*/
|
||||
LiveLockScreenInfo getDefaultLiveLockScreen();
|
||||
|
||||
/**
|
||||
* Set the default Live lock screen. This is the Live lock screen that should be displayed
|
||||
* when no other Live lock screens are queued.
|
||||
*/
|
||||
void setDefaultLiveLockScreen(in LiveLockScreenInfo llsInfo);
|
||||
|
||||
/**
|
||||
* Set whether Live lock screen feature is enabled.
|
||||
*/
|
||||
oneway void setLiveLockScreenEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Get the enabled state of the Live lock screen feature.
|
||||
*/
|
||||
boolean getLiveLockScreenEnabled();
|
||||
|
||||
/**
|
||||
* Registers an ILiveLockScreenChangeListener that will be called when the current Live lock
|
||||
* screen changes.
|
||||
*/
|
||||
boolean registerChangeListener(in ILiveLockScreenChangeListener listener);
|
||||
|
||||
/**
|
||||
* Unregisters a previously registered ILiveLockScreenChangeListener.
|
||||
*/
|
||||
boolean unregisterChangeListener(in ILiveLockScreenChangeListener listener);
|
||||
}
|
65
src/java/cyanogenmod/app/ILiveLockScreenManagerProvider.aidl
Normal file
65
src/java/cyanogenmod/app/ILiveLockScreenManagerProvider.aidl
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
** Copyright (C) 2016 The CyanogenMod Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import cyanogenmod.app.ILiveLockScreenChangeListener;
|
||||
import cyanogenmod.app.LiveLockScreenInfo;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by services that support the
|
||||
* {@link LiveLockScreenManager#SERVICE_INTERFACE}
|
||||
* @hide
|
||||
*/
|
||||
interface ILiveLockScreenManagerProvider {
|
||||
|
||||
/**
|
||||
* Enqueue a Live lock screen to be displayed.
|
||||
*/
|
||||
void enqueueLiveLockScreen(String pkg, int id, in LiveLockScreenInfo lls,
|
||||
inout int[] idReceived, int userId);
|
||||
|
||||
/**
|
||||
* Cancel displaying a Live lock screen.
|
||||
*/
|
||||
void cancelLiveLockScreen(String pkg, int id, int userId);
|
||||
|
||||
/**
|
||||
* Get the current Live lock screen that should be displayed.
|
||||
*/
|
||||
LiveLockScreenInfo getCurrentLiveLockScreen();
|
||||
|
||||
/**
|
||||
* Called when the default Live lock screen has changed.
|
||||
*/
|
||||
oneway void updateDefaultLiveLockScreen(in LiveLockScreenInfo llsInfo);
|
||||
|
||||
/**
|
||||
* Get the enabled state of the Live lock screen feature.
|
||||
*/
|
||||
boolean getLiveLockScreenEnabled();
|
||||
|
||||
/**
|
||||
* Registers an ILiveLockScreenChangeListener that will be called when the current Live lock
|
||||
* screen changes.
|
||||
*/
|
||||
boolean registerChangeListener(in ILiveLockScreenChangeListener listener);
|
||||
|
||||
/**
|
||||
* Unregisters a previously registered ILiveLockScreenChangeListener.
|
||||
*/
|
||||
boolean unregisterChangeListener(in ILiveLockScreenChangeListener listener);
|
||||
}
|
19
src/java/cyanogenmod/app/LiveLockScreenInfo.aidl
Normal file
19
src/java/cyanogenmod/app/LiveLockScreenInfo.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
parcelable LiveLockScreenInfo;
|
196
src/java/cyanogenmod/app/LiveLockScreenInfo.java
Normal file
196
src/java/cyanogenmod/app/LiveLockScreenInfo.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import cyanogenmod.os.Build;
|
||||
|
||||
/**
|
||||
* Data structure defining a Live lock screen.
|
||||
*/
|
||||
public class LiveLockScreenInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* Default Live lock screen {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* Lower {@link #priority}, for items that are less important.
|
||||
*/
|
||||
public static final int PRIORITY_LOW = -1;
|
||||
|
||||
/**
|
||||
* Lowest {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_MIN = -2;
|
||||
|
||||
/**
|
||||
* Higher {@link #priority}, for items that are more important
|
||||
*/
|
||||
public static final int PRIORITY_HIGH = 1;
|
||||
|
||||
/**
|
||||
* Highest {@link #priority}.
|
||||
*/
|
||||
public static final int PRIORITY_MAX = 2;
|
||||
|
||||
/**
|
||||
* The component, which implements
|
||||
* {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService}, to display for this
|
||||
* live lock screen.
|
||||
*/
|
||||
public ComponentName component;
|
||||
|
||||
/**
|
||||
* Relative priority for this Live lock screen.
|
||||
*/
|
||||
public int priority;
|
||||
|
||||
/**
|
||||
* Constructs a LiveLockScreenInfo object with the given values.
|
||||
* You might want to consider using {@link Builder} instead.
|
||||
*/
|
||||
public LiveLockScreenInfo(@NonNull ComponentName component, int priority) {
|
||||
this.component = component;
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a LiveLockScreenInfo object with default values.
|
||||
* You might want to consider using {@link Builder} instead.
|
||||
*/
|
||||
public LiveLockScreenInfo()
|
||||
{
|
||||
this.component = null;
|
||||
this.priority = PRIORITY_DEFAULT;
|
||||
}
|
||||
|
||||
private LiveLockScreenInfo(Parcel source) {
|
||||
// Read parcelable version, make sure to define explicit changes
|
||||
// within {@link Build.PARCELABLE_VERSION);
|
||||
int version = source.readInt();
|
||||
int size = source.readInt();
|
||||
int start = source.dataPosition();
|
||||
|
||||
this.priority = source.readInt();
|
||||
String component = source.readString();
|
||||
this.component = !TextUtils.isEmpty(component)
|
||||
? ComponentName.unflattenFromString(component)
|
||||
: null;
|
||||
|
||||
source.setDataPosition(start + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Write parcelable version, make sure to define explicit changes
|
||||
// within {@link Build.PARCELABLE_VERSION);
|
||||
dest.writeInt(Build.PARCELABLE_VERSION);
|
||||
int sizePos = dest.dataPosition();
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
dest.writeInt(0);
|
||||
int dataStartPos = dest.dataPosition();
|
||||
|
||||
dest.writeInt(priority);
|
||||
dest.writeString(component != null ? component.flattenToString() : "");
|
||||
|
||||
// Go back and write size
|
||||
int size = dest.dataPosition() - dataStartPos;
|
||||
dest.setDataPosition(sizePos);
|
||||
dest.writeInt(size);
|
||||
dest.setDataPosition(dataStartPos + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LiveLockScreenInfo: priority=" + priority +
|
||||
", component=" + component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo clone() {
|
||||
LiveLockScreenInfo that = new LiveLockScreenInfo();
|
||||
cloneInto(that);
|
||||
return that;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
|
||||
* of this into that.
|
||||
* @hide
|
||||
*/
|
||||
public void cloneInto(LiveLockScreenInfo that) {
|
||||
that.component = this.component.clone();
|
||||
that.priority = this.priority;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<LiveLockScreenInfo> CREATOR =
|
||||
new Parcelable.Creator<LiveLockScreenInfo>() {
|
||||
@Override
|
||||
public LiveLockScreenInfo createFromParcel(Parcel source) {
|
||||
return new LiveLockScreenInfo(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveLockScreenInfo[] newArray(int size) {
|
||||
return new LiveLockScreenInfo[0];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder class for {@link LiveLockScreenInfo} objects. Provides a convenient way to set
|
||||
* various fields of a {@link LiveLockScreenInfo}.
|
||||
*/
|
||||
public static class Builder {
|
||||
private int mPriority;
|
||||
private ComponentName mComponent;
|
||||
|
||||
public Builder setPriority(int priority) {
|
||||
if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
|
||||
throw new IllegalArgumentException("Invalid priorty given (" + priority + "): " +
|
||||
PRIORITY_MIN + " <= priority <= " + PRIORITY_MIN);
|
||||
}
|
||||
mPriority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setComponent(@NonNull ComponentName component) {
|
||||
if (component == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot call setComponent with a null component");
|
||||
}
|
||||
mComponent = component;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiveLockScreenInfo build() {
|
||||
return new LiveLockScreenInfo(mComponent, mPriority);
|
||||
}
|
||||
}
|
||||
}
|
182
src/java/cyanogenmod/app/LiveLockScreenManager.java
Normal file
182
src/java/cyanogenmod/app/LiveLockScreenManager.java
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Manages enabling/disabling Live lock screens as well as what Live lock screen to display when
|
||||
* enabled.
|
||||
*/
|
||||
public class LiveLockScreenManager {
|
||||
private static final String TAG = LiveLockScreenManager.class.getSimpleName();
|
||||
private static ILiveLockScreenManager sService;
|
||||
private static LiveLockScreenManager sInstance;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
/**
|
||||
* The {@link android.content.Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_INTERFACE
|
||||
= "cyanogenmod.app.LiveLockScreenManagerService";
|
||||
|
||||
private LiveLockScreenManager(Context context) {
|
||||
mContext = context;
|
||||
sService = getService();
|
||||
if (context.getPackageManager().hasSystemFeature(
|
||||
CMContextConstants.Features.LIVE_LOCK_SCREEN) && sService == null) {
|
||||
throw new RuntimeException("Unable to get LiveLockScreenManagerService. " +
|
||||
"The service either crashed, was not started, or the interface has " +
|
||||
"been called to early in SystemServer init");
|
||||
}
|
||||
}
|
||||
|
||||
private ILiveLockScreenManager getService() {
|
||||
if (sService == null) {
|
||||
IBinder b = ServiceManager.getService(CMContextConstants.CM_LIVE_LOCK_SCREEN_SERVICE);
|
||||
if (b != null) {
|
||||
sService = ILiveLockScreenManager.Stub.asInterface(b);
|
||||
}
|
||||
}
|
||||
|
||||
return sService;
|
||||
}
|
||||
|
||||
private void logServiceException(Exception e) {
|
||||
Log.w(TAG, "Unable to access LiveLockScreenServiceBroker", e);
|
||||
}
|
||||
|
||||
public static LiveLockScreenManager getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new LiveLockScreenManager(context);
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a Live lock screen, defined in {@param lls}, to be displayed with the given id.
|
||||
* @param id An identifier for this notification unique within your application.
|
||||
* @param llsInfo A {@link LiveLockScreenInfo} object describing what Live lock screen to show
|
||||
* the user.
|
||||
* @return True if the Live lock screen was successfully received by the backing service
|
||||
*/
|
||||
public boolean show(int id, @NonNull final LiveLockScreenInfo llsInfo) {
|
||||
int[] idOut = new int[1];
|
||||
String pkg = mContext.getPackageName();
|
||||
boolean success = true;
|
||||
try {
|
||||
sService.enqueueLiveLockScreen(pkg, id, llsInfo, idOut, UserHandle.myUserId());
|
||||
if (id != idOut[0]) {
|
||||
Log.w(TAG, "show: id corrupted: sent " + id + ", got back " + idOut[0]);
|
||||
success = false;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a previously shown Live lock screen.
|
||||
* @param id An identifier for this notification unique within your application.
|
||||
*/
|
||||
public void cancel(int id) {
|
||||
String pkg = mContext.getPackageName();
|
||||
try {
|
||||
sService.cancelLiveLockScreen(pkg, id, UserHandle.myUserId());
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default Live lock screen to display when no other Live lock screens are queued
|
||||
* up for display.
|
||||
* <p>
|
||||
* This is not available to third party applications.
|
||||
* </p>
|
||||
*/
|
||||
public void setDefaultLiveLockScreen(@Nullable LiveLockScreenInfo llsInfo) {
|
||||
try {
|
||||
sService.setDefaultLiveLockScreen(llsInfo);
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default Live lock screen that is displayed when no other Live lock screens are
|
||||
* queued up for display.
|
||||
* <p>
|
||||
* This is not available to third party applications.
|
||||
* </p>
|
||||
*/
|
||||
public LiveLockScreenInfo getDefaultLiveLockScreen() {
|
||||
try {
|
||||
return sService.getDefaultLiveLockScreen();
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public LiveLockScreenInfo getCurrentLiveLockScreen() {
|
||||
LiveLockScreenInfo lls = null;
|
||||
try {
|
||||
lls = sService.getCurrentLiveLockScreen();
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
|
||||
return lls;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean getLiveLockScreenEnabled() {
|
||||
try {
|
||||
return sService.getLiveLockScreenEnabled();
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setLiveLockScreenEnabled(boolean enabled) {
|
||||
try {
|
||||
sService.setLiveLockScreenEnabled(enabled);
|
||||
} catch (RemoteException e) {
|
||||
logServiceException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -2648,6 +2648,13 @@ public final class CMSettings {
|
||||
*/
|
||||
public static final String LIVE_LOCK_SCREEN_ENABLED = "live_lock_screen_enabled";
|
||||
|
||||
/**
|
||||
* The user selected Live lock screen to display
|
||||
* @hide
|
||||
*/
|
||||
public static final String DEFAULT_LIVE_LOCK_SCREEN_COMPONENT =
|
||||
"default_live_lock_screen_component";
|
||||
|
||||
/**
|
||||
* Whether keyguard will direct show security view (0 = false, 1 = true)
|
||||
* @hide
|
||||
|
@ -196,6 +196,38 @@ package cyanogenmod.app {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "cyanogenmod.app.CustomTileListenerService";
|
||||
}
|
||||
|
||||
public class LiveLockScreenInfo implements android.os.Parcelable {
|
||||
ctor public LiveLockScreenInfo(android.content.ComponentName, int);
|
||||
ctor public LiveLockScreenInfo();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo clone();
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<cyanogenmod.app.LiveLockScreenInfo> CREATOR;
|
||||
field public static final int PRIORITY_DEFAULT = 0; // 0x0
|
||||
field public static final int PRIORITY_HIGH = 1; // 0x1
|
||||
field public static final int PRIORITY_LOW = -1; // 0xffffffff
|
||||
field public static final int PRIORITY_MAX = 2; // 0x2
|
||||
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
|
||||
field public android.content.ComponentName component;
|
||||
field public int priority;
|
||||
}
|
||||
|
||||
public static class LiveLockScreenInfo.Builder {
|
||||
ctor public LiveLockScreenInfo.Builder();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo build();
|
||||
method public cyanogenmod.app.LiveLockScreenInfo.Builder setComponent(android.content.ComponentName);
|
||||
method public cyanogenmod.app.LiveLockScreenInfo.Builder setPriority(int);
|
||||
}
|
||||
|
||||
public class LiveLockScreenManager {
|
||||
method public void cancel(int);
|
||||
method public cyanogenmod.app.LiveLockScreenInfo getDefaultLiveLockScreen();
|
||||
method public static cyanogenmod.app.LiveLockScreenManager getInstance(android.content.Context);
|
||||
method public void setDefaultLiveLockScreen(cyanogenmod.app.LiveLockScreenInfo);
|
||||
method public boolean show(int, cyanogenmod.app.LiveLockScreenInfo);
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "cyanogenmod.app.LiveLockScreenManagerService";
|
||||
}
|
||||
|
||||
public class PartnerInterface {
|
||||
method public java.lang.String getCurrentHotwordPackageName();
|
||||
method public static cyanogenmod.app.PartnerInterface getInstance(android.content.Context);
|
||||
@ -564,6 +596,7 @@ package cyanogenmod.platform {
|
||||
field public static final java.lang.String ACCESS_APP_SUGGESTIONS = "cyanogenmod.permission.ACCESS_APP_SUGGESTIONS";
|
||||
field public static final java.lang.String ACCESS_THEME_MANAGER = "cyanogenmod.permission.ACCESS_THEME_MANAGER";
|
||||
field public static final java.lang.String HARDWARE_ABSTRACTION_ACCESS = "cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS";
|
||||
field public static final java.lang.String LIVE_LOCK_SCREEN_MANAGER_ACCESS = "cyanogenmod.permission.LIVE_LOCK_SCREEN_MANAGER_ACCESS";
|
||||
field public static final java.lang.String MANAGE_ALARMS = "cyanogenmod.permission.MANAGE_ALARMS";
|
||||
field public static final java.lang.String MANAGE_PERSISTENT_STORAGE = "cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE";
|
||||
field public static final java.lang.String MODIFY_MSIM_PHONE_STATE = "cyanogenmod.permission.MODIFY_MSIM_PHONE_STATE";
|
||||
|
Loading…
Reference in New Issue
Block a user