CMSDK: Create Quick Settings Tile API.
Create a simple CustomTile object with builder which lets a 3rd party
application publish a quick settings tile to the status bar panel.
An example CustomTile build:
CustomTile customTile = new CustomTile.Builder(mContext)
.setLabel("custom label")
.setContentDescription("custom description")
.setOnClickIntent(pendingIntent)
.setOnClickUri(Uri.parse("custom uri"))
.setIcon(R.drawable.ic_launcher)
.build();
Which can be published to the status bar panel via CMStatusBarManager#publishTile.
The CustomTile contains a click intent and click uri which can be
sent or broadcasted when the CustomQSTile's handleClick is fired.
This implementation closely mirrors that of NotificationManager#notify for
notifications. In that each CMStatusBarManager#publishTile can have an appended
id which can be kept by the 3rd party application to either update the tile with,
or to remove the tile via CMStatusBarManager#removeTile.
Change-Id: I4b8a50e4e53ef2ececc9c7fc9c8d0ec6acfd0c0e
This commit is contained in:
42
src/java/cyanogenmod/app/CMContextConstants.java
Normal file
42
src/java/cyanogenmod/app/CMContextConstants.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
/**
|
||||
* Constants to be used with {@link android.content.Context#getSystemService}
|
||||
* to retrieve published system services
|
||||
*/
|
||||
public class CMContextConstants {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private CMContextConstants() {
|
||||
// Empty constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with {@link android.content.Context#getSystemService} to retrieve a
|
||||
* {@link cyanogenmod.app.CMStatusBarManager} for informing the user of
|
||||
* background events.
|
||||
*
|
||||
* @see android.content.Context#getSystemService
|
||||
* @see cyanogenmod.app.CMStatusBarManager
|
||||
*/
|
||||
public static final String CM_STATUS_BAR_SERVICE = "cmstatusbar";
|
||||
|
||||
}
|
||||
215
src/java/cyanogenmod/app/CMStatusBarManager.java
Normal file
215
src/java/cyanogenmod/app/CMStatusBarManager.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import cyanogenmod.app.ICMStatusBarManager;
|
||||
|
||||
/**
|
||||
* The CMStatusBarManager allows you to publish and remove CustomTiles within the
|
||||
* Quick Settings Panel.
|
||||
*
|
||||
* <p>
|
||||
* Each of the publish methods takes an int id parameter and optionally a
|
||||
* {@link String} tag parameter, which may be {@code null}. These parameters
|
||||
* are used to form a pair (tag, id), or ({@code null}, id) if tag is
|
||||
* unspecified. This pair identifies this custom tile from your app to the
|
||||
* system, so that pair should be unique within your app. If you call one
|
||||
* of the publish methods with a (tag, id) pair that is currently active and
|
||||
* a new set of custom tile parameters, it will be updated. For example,
|
||||
* if you pass a new custom tile icon, the old icon in the panel will
|
||||
* be replaced with the new one. This is also the same tag and id you pass
|
||||
* to the {@link #removeTile(int)} or {@link #removeTile(String, int)} method to clear
|
||||
* this custom tile.
|
||||
*
|
||||
* <p>
|
||||
* To get the instance of this class, utilize CMStatusBarManager#getInstance(Context context)
|
||||
*
|
||||
* @see cyanogenmod.app.CustomTile
|
||||
*/
|
||||
public class CMStatusBarManager {
|
||||
private static final String TAG = "CMStatusBarManager";
|
||||
private static boolean localLOGV = false;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private static ICMStatusBarManager sService;
|
||||
|
||||
private static CMStatusBarManager sCMStatusBarManagerInstance;
|
||||
private CMStatusBarManager(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
if (appContext != null) {
|
||||
mContext = appContext;
|
||||
} else {
|
||||
mContext = context;
|
||||
}
|
||||
sService = getService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create an instance of the {@link cyanogenmod.app.CMStatusBarManager}
|
||||
* @param context
|
||||
* @return {@link cyanogenmod.app.CMStatusBarManager}
|
||||
*/
|
||||
public static CMStatusBarManager getInstance(Context context) {
|
||||
if (sCMStatusBarManagerInstance == null) {
|
||||
sCMStatusBarManagerInstance = new CMStatusBarManager(context);
|
||||
}
|
||||
return sCMStatusBarManagerInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a custom tile to be shown in the status bar panel. If a custom tile with
|
||||
* the same id has already been posted by your application and has not yet been removed, it
|
||||
* will be replaced by the updated information.
|
||||
*
|
||||
* @param id An identifier for this customTile unique within your
|
||||
* application.
|
||||
* @param customTile A {@link CustomTile} object describing what to show the user.
|
||||
* Must not be null.
|
||||
*/
|
||||
public void publishTile(int id, CustomTile customTile) {
|
||||
publishTile(null, id, customTile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a custom tile to be shown in the status bar panel. If a custom tile with
|
||||
* the same tag and id has already been posted by your application and has not yet been
|
||||
* removed, it will be replaced by the updated information.
|
||||
*
|
||||
* @param tag A string identifier for this custom tile. May be {@code null}.
|
||||
* @param id An identifier for this custom tile. The pair (tag, id) must be unique
|
||||
* within your application.
|
||||
* @param customTile A {@link cyanogenmod.app.CustomTile} object describing what to
|
||||
* show the user. Must not be null.
|
||||
*/
|
||||
public void publishTile(String tag, int id, CustomTile customTile) {
|
||||
if (sService == null) {
|
||||
Log.w(TAG, "not connected to CMStatusBarManagerService");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] idOut = new int[1];
|
||||
String pkg = mContext.getPackageName();
|
||||
if (localLOGV) Log.v(TAG, pkg + ": create(" + id + ", " + customTile + ")");
|
||||
try {
|
||||
sService.createCustomTileWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
customTile, idOut, UserHandle.myUserId());
|
||||
if (id != idOut[0]) {
|
||||
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w("CMStatusBarManager", "warning: no cm status bar service");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link cyanogenmod.app.CMStatusBarManager#publishTile(int id, cyanogenmod.app.CustomTile)},
|
||||
* however lets you specify a {@link android.os.UserHandle}
|
||||
* @param tag A string identifier for this custom tile. May be {@code null}.
|
||||
* @param id An identifier for this custom tile. The pair (tag, id) must be unique
|
||||
* within your application.
|
||||
* @param customTile A {@link cyanogenmod.app.CustomTile} object describing what to
|
||||
* show the user. Must not be null.
|
||||
* @param user A user handle to publish the tile as.
|
||||
*/
|
||||
public void publishTileAsUser(String tag, int id, CustomTile customTile, UserHandle user) {
|
||||
if (sService == null) {
|
||||
Log.w(TAG, "not connected to CMStatusBarManagerService");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] idOut = new int[1];
|
||||
String pkg = mContext.getPackageName();
|
||||
if (localLOGV) Log.v(TAG, pkg + ": create(" + id + ", " + customTile + ")");
|
||||
try {
|
||||
sService.createCustomTileWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
customTile, idOut, user.getIdentifier());
|
||||
if (id != idOut[0]) {
|
||||
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w("CMStatusBarManager", "warning: no cm status bar service");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a custom tile that's currently published to the StatusBarPanel.
|
||||
* @param id The identifier for the custom tile to be removed.
|
||||
*/
|
||||
public void removeTile(int id) {
|
||||
removeTile(null, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a custom tile that's currently published to the StatusBarPanel.
|
||||
* @param tag The string identifier for the custom tile to be removed.
|
||||
* @param id The identifier for the custom tile to be removed.
|
||||
*/
|
||||
public void removeTile(String tag, int id) {
|
||||
if (sService == null) {
|
||||
Log.w(TAG, "not connected to CMStatusBarManagerService");
|
||||
return;
|
||||
}
|
||||
|
||||
String pkg = mContext.getPackageName();
|
||||
if (localLOGV) Log.v(TAG, pkg + ": remove(" + id + ")");
|
||||
try {
|
||||
sService.removeCustomTileWithTag(pkg, tag, id, UserHandle.myUserId());
|
||||
} catch (RemoteException e) {
|
||||
Slog.w("CMStatusBarManager", "warning: no cm status bar service");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link cyanogenmod.app.CMStatusBarManager#removeTile(String tag, int id)} however lets you
|
||||
* specific a {@link android.os.UserHandle}
|
||||
* @param tag The string identifier for the custom tile to be removed.
|
||||
* @param id The identifier for the custom tile to be removed.
|
||||
* @param user The user handle to remove the tile from.
|
||||
*/
|
||||
public void removeTileAsUser(String tag, int id, UserHandle user) {
|
||||
if (sService == null) {
|
||||
Log.w(TAG, "not connected to CMStatusBarManagerService");
|
||||
return;
|
||||
}
|
||||
|
||||
String pkg = mContext.getPackageName();
|
||||
if (localLOGV) Log.v(TAG, pkg + ": remove(" + id + ")");
|
||||
try {
|
||||
sService.removeCustomTileWithTag(pkg, tag, id, user.getIdentifier());
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public ICMStatusBarManager getService() {
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
}
|
||||
IBinder b = ServiceManager.getService(CMContextConstants.CM_STATUS_BAR_SERVICE);
|
||||
sService = ICMStatusBarManager.Stub.asInterface(b);
|
||||
return sService;
|
||||
}
|
||||
}
|
||||
19
src/java/cyanogenmod/app/CustomTile.aidl
Normal file
19
src/java/cyanogenmod/app/CustomTile.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
parcelable CustomTile;
|
||||
296
src/java/cyanogenmod/app/CustomTile.java
Normal file
296
src/java/cyanogenmod/app/CustomTile.java
Normal file
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* A class that represents a quick settings tile
|
||||
*
|
||||
* <p>The {@link cyanogenmod.app.CustomTile.Builder} has been added to make it
|
||||
* easier to construct CustomTiles.</p>
|
||||
*/
|
||||
public class CustomTile implements Parcelable {
|
||||
|
||||
/**
|
||||
* An optional intent to execute when the custom tile entry is clicked. If
|
||||
* this is an activity, it must include the
|
||||
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
|
||||
* that you take care of task management
|
||||
**/
|
||||
public PendingIntent onClick;
|
||||
|
||||
/**
|
||||
* An optional Uri to be parsed and broadcast on tile click
|
||||
**/
|
||||
public Uri onClickUri;
|
||||
|
||||
/**
|
||||
* A label specific to the quick settings tile to be created
|
||||
*/
|
||||
public String label;
|
||||
|
||||
/**
|
||||
* A content description for the custom tile state
|
||||
*/
|
||||
public String contentDescription;
|
||||
|
||||
/**
|
||||
* An icon to represent the custom tile
|
||||
*/
|
||||
public int icon;
|
||||
|
||||
/**
|
||||
* Unflatten the CustomTile from a parcel.
|
||||
*/
|
||||
public CustomTile(Parcel parcel)
|
||||
{
|
||||
if (parcel.readInt() != 0) {
|
||||
this.onClick = PendingIntent.CREATOR.createFromParcel(parcel);
|
||||
}
|
||||
if (parcel.readInt() != 0) {
|
||||
this.onClickUri = Uri.CREATOR.createFromParcel(parcel);
|
||||
}
|
||||
if (parcel.readInt() != 0) {
|
||||
this.label = parcel.readString();
|
||||
}
|
||||
|
||||
if (parcel.readInt() != 0) {
|
||||
this.contentDescription = parcel.readString();
|
||||
}
|
||||
this.icon = parcel.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CustomTile object with default values.
|
||||
* You might want to consider using {@link cyanogenmod.app.CustomTile.Builder} instead.
|
||||
*/
|
||||
public CustomTile()
|
||||
{
|
||||
// Empty constructor
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTile clone() {
|
||||
CustomTile that = new CustomTile();
|
||||
cloneInto(that);
|
||||
return that;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
String NEW_LINE = System.getProperty("line.separator");
|
||||
if (onClickUri != null) {
|
||||
b.append("onClickUri=" + onClickUri.toString() + NEW_LINE);
|
||||
}
|
||||
if (onClick != null) {
|
||||
b.append("onClick=" + onClick.toString() + NEW_LINE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(label)) {
|
||||
b.append("label=" + label + NEW_LINE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(contentDescription)) {
|
||||
b.append("contentDescription=" + contentDescription + NEW_LINE);
|
||||
}
|
||||
b.append("icon=" + icon + NEW_LINE);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all of this into that
|
||||
* @hide
|
||||
*/
|
||||
public void cloneInto(CustomTile that) {
|
||||
that.onClick = this.onClick;
|
||||
that.onClickUri = this.onClickUri;
|
||||
that.label = this.label;
|
||||
that.contentDescription = this.contentDescription;
|
||||
that.icon = this.icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
if (onClick != null) {
|
||||
out.writeInt(1);
|
||||
onClick.writeToParcel(out, 0);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
if (onClickUri != null) {
|
||||
out.writeInt(1);
|
||||
onClickUri.writeToParcel(out, 0);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
if (label != null) {
|
||||
out.writeInt(1);
|
||||
out.writeString(label);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
if (contentDescription != null) {
|
||||
out.writeInt(1);
|
||||
out.writeString(contentDescription);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
out.writeInt(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable.Creator that instantiates CustomTile objects
|
||||
*/
|
||||
public static final Creator<CustomTile> CREATOR =
|
||||
new Creator<CustomTile>() {
|
||||
public CustomTile createFromParcel(Parcel in) {
|
||||
return new CustomTile(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTile[] newArray(int size) {
|
||||
return new CustomTile[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder class for {@link cyanogenmod.app.CustomTile} objects.
|
||||
*
|
||||
* Provides a convenient way to set the various fields of a {@link cyanogenmod.app.CustomTile}
|
||||
*
|
||||
* <p>Example:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* CustomTile customTile = new CustomTile.Builder(mContext)
|
||||
* .setLabel("custom label")
|
||||
* .setContentDescription("custom description")
|
||||
* .setOnClickIntent(pendingIntent)
|
||||
* .setOnClickUri(Uri.parse("custom uri"))
|
||||
* .setIcon(R.drawable.ic_launcher)
|
||||
* .build();
|
||||
* </pre>
|
||||
*/
|
||||
public static class Builder {
|
||||
private PendingIntent mOnClick;
|
||||
private Uri mOnClickUri;
|
||||
private String mLabel;
|
||||
private String mContentDescription;
|
||||
private int mIcon;
|
||||
private Context mContext;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the defaults:
|
||||
*/
|
||||
public Builder(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label for the custom tile
|
||||
* @param label a string to be used for the custom tile label
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setLabel(String label) {
|
||||
mLabel = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label for the custom tile
|
||||
* @param id a string resource id to be used for the custom tile label
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setLabel(int id) {
|
||||
mLabel = mContext.getString(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content description for the custom tile
|
||||
* @param contentDescription a string to explain content
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setContentDescription(String contentDescription) {
|
||||
mContentDescription = contentDescription;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content description for the custom tile
|
||||
* @param id a string resource id to explain content
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setContentDescription(int id) {
|
||||
mContentDescription = mContext.getString(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link android.app.PendingIntent} to be fired on custom tile click
|
||||
* @param intent
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setOnClickIntent(PendingIntent intent) {
|
||||
mOnClick = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link android.net.Uri} to be broadcasted in an intent on custom tile click
|
||||
* @param uri
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setOnClickUri(Uri uri) {
|
||||
mOnClickUri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an icon for the custom tile to be presented to the user
|
||||
* @param drawableId
|
||||
* @return {@link cyanogenmod.app.CustomTile.Builder}
|
||||
*/
|
||||
public Builder setIcon(int drawableId) {
|
||||
mIcon = drawableId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link cyanogenmod.app.CustomTile} object
|
||||
* @return {@link cyanogenmod.app.CustomTile}
|
||||
*/
|
||||
public CustomTile build() {
|
||||
CustomTile tile = new CustomTile();
|
||||
tile.onClick = mOnClick;
|
||||
tile.onClickUri = mOnClickUri;
|
||||
tile.label = mLabel;
|
||||
tile.contentDescription = mContentDescription;
|
||||
tile.icon = mIcon;
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
194
src/java/cyanogenmod/app/CustomTileListenerService.java
Normal file
194
src/java/cyanogenmod/app/CustomTileListenerService.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import cyanogenmod.app.ICustomTileListener;
|
||||
import cyanogenmod.app.ICMStatusBarManager;
|
||||
|
||||
import org.cyanogenmod.internal.statusbar.IStatusBarCustomTileHolder;
|
||||
|
||||
/**
|
||||
* A service that receives calls from the system when new custom tiles are
|
||||
* posted or removed.
|
||||
* <p>To extend this class, you must declare the service in your manifest file with
|
||||
* the TODO: add permission
|
||||
* and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
|
||||
* <pre>
|
||||
* <service android:name=".CustomTileListener"
|
||||
* android:label="@string/service_name"
|
||||
* android:permission="TODO: Add me">
|
||||
* <intent-filter>
|
||||
* <action android:name="cyanogenmod.app.CustomTileListenerService" />
|
||||
* </intent-filter>
|
||||
* </service></pre>
|
||||
*/
|
||||
public class CustomTileListenerService extends Service {
|
||||
private final String TAG = CustomTileListenerService.class.getSimpleName()
|
||||
+ "[" + getClass().getSimpleName() + "]";
|
||||
/**
|
||||
* 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.CustomTileListenerService";
|
||||
|
||||
private ICustomTileListenerWrapper mWrapper = null;
|
||||
private ICMStatusBarManager mStatusBarService;
|
||||
/** Only valid after a successful call to (@link registerAsService}. */
|
||||
private int mCurrentUser;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new ICustomTileListenerWrapper();
|
||||
}
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
private final ICMStatusBarManager getStatusBarInterface() {
|
||||
if (mStatusBarService == null) {
|
||||
mStatusBarService = ICMStatusBarManager.Stub.asInterface(
|
||||
ServiceManager.getService(CMContextConstants.CM_STATUS_BAR_SERVICE));
|
||||
}
|
||||
return mStatusBarService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly register this service with the StatusBar Manager.
|
||||
*
|
||||
* <p>Only system services may use this call. It will fail for non-system callers.
|
||||
* Apps should ask the user to add their listener in Settings.
|
||||
*
|
||||
* @param context Context required for accessing resources. Since this service isn't
|
||||
* launched as a real Service when using this method, a context has to be passed in.
|
||||
* @param componentName the component that will consume the custom tile information
|
||||
* @param currentUser the user to use as the stream filter
|
||||
* @hide
|
||||
*/
|
||||
public void registerAsSystemService(Context context, ComponentName componentName,
|
||||
int currentUser) throws RemoteException {
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new ICustomTileListenerWrapper();
|
||||
}
|
||||
ICMStatusBarManager statusBarInterface = getStatusBarInterface();
|
||||
statusBarInterface.registerListener(mWrapper, componentName, currentUser);
|
||||
mCurrentUser = currentUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly unregister this service from the StatusBar Manager.
|
||||
*
|
||||
* <P>This method will fail for listeners that were not registered
|
||||
* with (@link registerAsService).
|
||||
* @hide
|
||||
*/
|
||||
public void unregisterAsSystemService() throws RemoteException {
|
||||
if (mWrapper != null) {
|
||||
ICMStatusBarManager statusBarInterface = getStatusBarInterface();
|
||||
statusBarInterface.unregisterListener(mWrapper, mCurrentUser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class ICustomTileListenerWrapper extends ICustomTileListener.Stub {
|
||||
@Override
|
||||
public void onListenerConnected() {
|
||||
synchronized (mWrapper) {
|
||||
try {
|
||||
CustomTileListenerService.this.onListenerConnected();
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onListenerConnected", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onCustomTilePosted(IStatusBarCustomTileHolder sbcHolder) {
|
||||
StatusBarPanelCustomTile sbc;
|
||||
try {
|
||||
sbc = sbcHolder.get();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "onCustomTilePosted: Error receiving StatusBarPanelCustomTile", e);
|
||||
return;
|
||||
}
|
||||
synchronized (mWrapper) {
|
||||
try {
|
||||
CustomTileListenerService.this.onCustomTilePosted(sbc);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onCustomTilePosted", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onCustomTileRemoved(IStatusBarCustomTileHolder sbcHolder) {
|
||||
StatusBarPanelCustomTile sbc;
|
||||
try {
|
||||
sbc = sbcHolder.get();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "onCustomTileRemoved: Error receiving StatusBarPanelCustomTile", e);
|
||||
return;
|
||||
}
|
||||
synchronized (mWrapper) {
|
||||
try {
|
||||
CustomTileListenerService.this.onCustomTileRemoved(sbc);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onCustomTileRemoved", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to learn about new custom tiles as they are posted by apps.
|
||||
*
|
||||
* @param sbc A data structure encapsulating the original {@link cyanogenmod.app.CustomTile}
|
||||
* object as well as its identifying information (tag and id) and source
|
||||
* (package name).
|
||||
*/
|
||||
public void onCustomTilePosted(StatusBarPanelCustomTile sbc) {
|
||||
// optional
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to learn when custom tiles are removed.
|
||||
*
|
||||
* @param sbc A data structure encapsulating at least the original information (tag and id)
|
||||
* and source (package name) used to post the {@link cyanogenmod.app.CustomTile} that
|
||||
* was just removed.
|
||||
*/
|
||||
public void onCustomTileRemoved(StatusBarPanelCustomTile sbc) {
|
||||
// optional
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to learn about when the listener is enabled and connected to
|
||||
* the status bar manager.
|
||||
* at this time.
|
||||
*/
|
||||
public void onListenerConnected() {
|
||||
// optional
|
||||
}
|
||||
}
|
||||
37
src/java/cyanogenmod/app/ICMStatusBarManager.aidl
Normal file
37
src/java/cyanogenmod/app/ICMStatusBarManager.aidl
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import android.content.ComponentName;
|
||||
|
||||
import cyanogenmod.app.CustomTile;
|
||||
import cyanogenmod.app.ICustomTileListener;
|
||||
|
||||
/** @hide */
|
||||
interface ICMStatusBarManager {
|
||||
// --- Methods below are for use by 3rd party applications to publish quick
|
||||
// settings tiles to the status bar panel
|
||||
// You need the PUBLISH_QUICK_SETTINGS_TILE permission
|
||||
void createCustomTileWithTag(String pkg, String opPkg, String tag, int id,
|
||||
in CustomTile tile, inout int[] idReceived, int userId);
|
||||
void removeCustomTileWithTag(String pkg, String tag, int id, int userId);
|
||||
|
||||
// --- Methods below are for use by 3rd party applications
|
||||
// You need the BIND_QUICK_SETTINGS_TILE_LISTENER permission
|
||||
void registerListener(in ICustomTileListener listener, in ComponentName component, int userid);
|
||||
void unregisterListener(in ICustomTileListener listener, int userid);
|
||||
}
|
||||
29
src/java/cyanogenmod/app/ICustomTileListener.aidl
Normal file
29
src/java/cyanogenmod/app/ICustomTileListener.aidl
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import cyanogenmod.app.StatusBarPanelCustomTile;
|
||||
|
||||
import org.cyanogenmod.internal.statusbar.IStatusBarCustomTileHolder;
|
||||
|
||||
/** @hide */
|
||||
oneway interface ICustomTileListener
|
||||
{
|
||||
void onListenerConnected();
|
||||
void onCustomTilePosted(in IStatusBarCustomTileHolder customTileHolder);
|
||||
void onCustomTileRemoved(in IStatusBarCustomTileHolder customTileHolder);
|
||||
}
|
||||
20
src/java/cyanogenmod/app/StatusBarPanelCustomTile.aidl
Normal file
20
src/java/cyanogenmod/app/StatusBarPanelCustomTile.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
parcelable StatusBarPanelCustomTile;
|
||||
|
||||
193
src/java/cyanogenmod/app/StatusBarPanelCustomTile.java
Normal file
193
src/java/cyanogenmod/app/StatusBarPanelCustomTile.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 cyanogenmod.app;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Class encapsulating a Custom Tile. Sent by the StatusBarManagerService to clients including
|
||||
* the status bar panel and any {@link cyanogenmod.app.CustomTileListenerService} clients.
|
||||
*/
|
||||
public class StatusBarPanelCustomTile implements Parcelable {
|
||||
|
||||
private final String pkg;
|
||||
private final int id;
|
||||
private final String tag;
|
||||
private final String key;
|
||||
|
||||
private final int uid;
|
||||
private final String opPkg;
|
||||
private final int initialPid;
|
||||
private final CustomTile customTile;
|
||||
private final UserHandle user;
|
||||
private final long postTime;
|
||||
|
||||
public StatusBarPanelCustomTile(String pkg, String opPkg, int id, String tag, int uid,
|
||||
int initialPid, CustomTile customTile, UserHandle user) {
|
||||
this(pkg, opPkg, id, tag, uid, initialPid, customTile, user,
|
||||
System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public StatusBarPanelCustomTile(String pkg, String opPkg, int id, String tag, int uid,
|
||||
int initialPid, CustomTile customTile, UserHandle user,
|
||||
long postTime) {
|
||||
if (pkg == null) throw new NullPointerException();
|
||||
if (customTile == null) throw new NullPointerException();
|
||||
|
||||
this.pkg = pkg;
|
||||
this.opPkg = opPkg;
|
||||
this.id = id;
|
||||
this.tag = tag;
|
||||
this.uid = uid;
|
||||
this.initialPid = initialPid;
|
||||
this.customTile = customTile;
|
||||
this.user = user;
|
||||
this.postTime = postTime;
|
||||
this.key = key();
|
||||
}
|
||||
|
||||
|
||||
public StatusBarPanelCustomTile(Parcel in) {
|
||||
this.pkg = in.readString();
|
||||
this.opPkg = in.readString();
|
||||
this.id = in.readInt();
|
||||
if (in.readInt() != 0) {
|
||||
this.tag = in.readString();
|
||||
} else {
|
||||
this.tag = null;
|
||||
}
|
||||
this.uid = in.readInt();
|
||||
this.initialPid = in.readInt();
|
||||
this.customTile = new CustomTile(in);
|
||||
this.user = UserHandle.readFromParcel(in);
|
||||
this.postTime = in.readLong();
|
||||
this.key = key();
|
||||
}
|
||||
|
||||
private String key() {
|
||||
return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
|
||||
}
|
||||
|
||||
public static final Creator<StatusBarPanelCustomTile> CREATOR
|
||||
= new Creator<StatusBarPanelCustomTile>()
|
||||
{
|
||||
public StatusBarPanelCustomTile createFromParcel(Parcel parcel)
|
||||
{
|
||||
return new StatusBarPanelCustomTile(parcel);
|
||||
}
|
||||
|
||||
public StatusBarPanelCustomTile[] newArray(int size)
|
||||
{
|
||||
return new StatusBarPanelCustomTile[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** The {@link cyanogenmod.app.CustomTile} supplied to
|
||||
* {@link cyanogenmod.app.CMStatusBarManager#publishTile(int, cyanogenmod.app.CustomTile)}.
|
||||
*/
|
||||
public CustomTile getCustomTile() {
|
||||
return customTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(this.pkg);
|
||||
out.writeString(this.opPkg);
|
||||
out.writeInt(this.id);
|
||||
if (this.tag != null) {
|
||||
out.writeInt(1);
|
||||
out.writeString(this.tag);
|
||||
} else {
|
||||
out.writeInt(0);
|
||||
}
|
||||
out.writeInt(this.uid);
|
||||
out.writeInt(this.initialPid);
|
||||
this.customTile.writeToParcel(out, flags);
|
||||
user.writeToParcel(out, flags);
|
||||
out.writeLong(this.postTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusBarPanelCustomTile clone() {
|
||||
return new StatusBarPanelCustomTile(this.pkg, this.opPkg,
|
||||
this.id, this.tag, this.uid, this.initialPid,
|
||||
this.customTile.clone(), this.user, this.postTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a userHandle for the instance of the app that posted this notification.
|
||||
*/
|
||||
public int getUserId() {
|
||||
return this.user.getIdentifier();
|
||||
}
|
||||
|
||||
/** The package of the app that posted the notification */
|
||||
public String getPackage() {
|
||||
return pkg;
|
||||
}
|
||||
|
||||
/** The id supplied to CMStatusBarManager */
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** The tag supplied to CMStatusBarManager or null if no tag was specified. */
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique instance key for this notification record.
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/** The notifying app's calling uid. @hide */
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/** The package used for AppOps tracking. @hide */
|
||||
public String getOpPkg() {
|
||||
return opPkg;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getInitialPid() {
|
||||
return initialPid;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link android.os.UserHandle} for whom this CustomTile is intended.
|
||||
*/
|
||||
public UserHandle getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/** The time (in {@link System#currentTimeMillis} time) the CustomTile was published, */
|
||||
public long getPostTime() {
|
||||
return postTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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 org.cyanogenmod.internal.statusbar;
|
||||
|
||||
import android.os.UserHandle;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import cyanogenmod.app.CustomTile;
|
||||
import cyanogenmod.app.StatusBarPanelCustomTile;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ExternalQuickSettingsRecord {
|
||||
public final StatusBarPanelCustomTile sbTile;
|
||||
public boolean isUpdate;
|
||||
public boolean isCanceled;
|
||||
|
||||
@VisibleForTesting
|
||||
public ExternalQuickSettingsRecord(StatusBarPanelCustomTile tile) {
|
||||
sbTile = tile;
|
||||
}
|
||||
|
||||
public CustomTile getCustomTile() {
|
||||
return sbTile.getCustomTile();
|
||||
}
|
||||
|
||||
public UserHandle getUser() {
|
||||
return sbTile.getUser();
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
return sbTile.getUserId();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return sbTile.getKey();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 org.cyanogenmod.internal.statusbar;
|
||||
|
||||
import cyanogenmod.app.StatusBarPanelCustomTile;
|
||||
|
||||
/** @hide */
|
||||
interface IStatusBarCustomTileHolder {
|
||||
/** Fetch the held StatusBarPanelCustomTile. This method should only be called once per Holder */
|
||||
StatusBarPanelCustomTile get();
|
||||
}
|
||||
Reference in New Issue
Block a user