diff options
author | Adnan Begovic <adnan@cyngn.com> | 2015-12-01 16:34:10 -0800 |
---|---|---|
committer | Adnan Begovic <adnan@cyngn.com> | 2015-12-07 15:24:06 -0800 |
commit | cf6674d766fe683e52e5c58e63152e9abd6ece89 (patch) | |
tree | 3b97dd23035ab50586b3ab55c9a824771cd7c4b7 | |
parent | 95cce6e3e8586592511c83ebde6edb51ee6fdd0f (diff) | |
download | frameworks_base-cf6674d766fe683e52e5c58e63152e9abd6ece89.zip frameworks_base-cf6674d766fe683e52e5c58e63152e9abd6ece89.tar.gz frameworks_base-cf6674d766fe683e52e5c58e63152e9abd6ece89.tar.bz2 |
SystemUi: Reintroduce custom qs tiles management.
Change-Id: I88dbf3911d4783de7c3f231aa57c51ce43bc8ae6
17 files changed, 505 insertions, 0 deletions
diff --git a/packages/SystemUI/AndroidManifest_cm.xml b/packages/SystemUI/AndroidManifest_cm.xml index a3ee433..187d3dc 100644 --- a/packages/SystemUI/AndroidManifest_cm.xml +++ b/packages/SystemUI/AndroidManifest_cm.xml @@ -21,6 +21,8 @@ <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" /> <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" /> + <!-- Quick Settings Tile Listener --> + <uses-permission android:name="cyanogenmod.permission.BIND_CUSTOM_TILE_LISTENER_SERVICE"/> <!-- Development shortcut --> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> diff --git a/packages/SystemUI/res/layout/qs_custom_detail.xml b/packages/SystemUI/res/layout/qs_custom_detail.xml new file mode 100644 index 0000000..f7a002e --- /dev/null +++ b/packages/SystemUI/res/layout/qs_custom_detail.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="8dp"> + + <LinearLayout android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="horizontal"> + + <ImageView android:id="@+id/custom_qs_tile_icon" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_marginEnd="12dp" /> + + <LinearLayout android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:orientation="vertical"> + + <TextView android:id="@+id/custom_qs_tile_title" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"/> + + <TextView android:id="@+id/custom_qs_tile_package " + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginTop="2dp" + android:textAppearance="@style/TextAppearance.QS.DetailItemSub"/> + + <TextView android:id="@+id/custom_qs_tile_content_description" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginTop="2dp" + android:textAppearance="@style/TextAppearance.QS.DetailItemSub" /> + + </LinearLayout> + + </LinearLayout> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml index ddff0f0..14ecd33 100644 --- a/packages/SystemUI/res/layout/qs_detail.xml +++ b/packages/SystemUI/res/layout/qs_detail.xml @@ -44,6 +44,16 @@ android:focusable="true" /> <TextView + android:id="@android:id/button3" + style="@style/QSBorderlessButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" + android:minWidth="88dp" + android:textAppearance="@style/TextAppearance.QS.DetailButton" + android:focusable="true" /> + + <TextView android:id="@android:id/button1" style="@style/QSBorderlessButton" android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/values/cm_strings.xml b/packages/SystemUI/res/values/cm_strings.xml index 7b56807..0750700 100644 --- a/packages/SystemUI/res/values/cm_strings.xml +++ b/packages/SystemUI/res/values/cm_strings.xml @@ -85,4 +85,7 @@ <!-- Screen pinning dialog description (for devices without navbar) --> <string name="screen_pinning_description_no_navbar">This keeps it in view until you unpin. Touch and hold the Back button to unpin.</string> + + <string name="quick_settings_custom_tile_detail_title">Custom Tile</string> + <string name="quick_settings_remove">Remove tile</string> </resources> diff --git a/packages/SystemUI/res/values/cm_styles.xml b/packages/SystemUI/res/values/cm_styles.xml index 36d8614..8caa89d 100644 --- a/packages/SystemUI/res/values/cm_styles.xml +++ b/packages/SystemUI/res/values/cm_styles.xml @@ -37,4 +37,8 @@ <item name="android:textColor">@color/status_bar_temperature_location_text_color</item> </style> + <style name="TextAppearance.QS.DetailItemSub"> + <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item> + </style> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 1cdaeb8..7d9b48b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController; import java.util.ArrayList; import java.util.Collection; +import cyanogenmod.app.StatusBarPanelCustomTile; import cyanogenmod.providers.CMSettings; /** View that represents the quick settings tile panel. **/ @@ -56,6 +57,7 @@ public class QSPanel extends ViewGroup { protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); protected View mDetail; protected ViewGroup mDetailContent; + protected TextView mDetailRemoveButton; protected TextView mDetailSettingsButton; protected TextView mDetailDoneButton; protected View mBrightnessView; @@ -96,6 +98,7 @@ public class QSPanel extends ViewGroup { protected void setupViews() { mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false); mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content); + mDetailRemoveButton = (TextView) mDetail.findViewById(android.R.id.button3); mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2); mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1); updateDetailText(); @@ -146,6 +149,7 @@ public class QSPanel extends ViewGroup { protected void updateDetailText() { mDetailDoneButton.setText(R.string.quick_settings_done); mDetailSettingsButton.setText(R.string.quick_settings_more_settings); + mDetailRemoveButton.setText(R.string.quick_settings_remove); } public void setBrightnessMirror(BrightnessMirrorController c) { @@ -197,6 +201,7 @@ public class QSPanel extends ViewGroup { super.onConfigurationChanged(newConfig); FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size); FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size); + FontSizeUtils.updateFontSize(mDetailRemoveButton, R.dimen.qs_detail_button_text_size); // We need to poke the detail views as well as they might not be attached to the view // hierarchy but reused at a later point. @@ -422,6 +427,16 @@ public class QSPanel extends ViewGroup { } }); + final StatusBarPanelCustomTile customTile = detailAdapter.getCustomTile(); + mDetailRemoveButton.setVisibility(customTile != null ? VISIBLE : GONE); + mDetailRemoveButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mHost.collapsePanels(); + mHost.removeCustomTile(customTile); + } + }); + mDetailContent.removeAllViews(); mDetail.bringToFront(); mDetailContent.addView(r.detailView); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 6fa304d..cdc68f2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RotationLockController; import com.android.systemui.statusbar.policy.ZenModeController; +import cyanogenmod.app.StatusBarPanelCustomTile; import java.util.Collection; import java.util.Objects; @@ -105,6 +106,7 @@ public abstract class QSTile<TState extends State> implements Listenable { Boolean getToggleState(); View createDetailView(Context context, View convertView, ViewGroup parent); Intent getSettingsIntent(); + StatusBarPanelCustomTile getCustomTile(); void setToggleState(boolean state); int getMetricsCategory(); } @@ -319,6 +321,7 @@ public abstract class QSTile<TState extends State> implements Listenable { } public interface Host { + void removeCustomTile(StatusBarPanelCustomTile customTile); void startActivityDismissingKeyguard(Intent intent); void warn(String message, Throwable t); void collapsePanels(); @@ -357,6 +360,42 @@ public abstract class QSTile<TState extends State> implements Listenable { } } + protected class ExternalIcon extends AnimationIcon { + private Context mPackageContext; + private String mPkg; + private int mResId; + + public ExternalIcon(String pkg, int resId) { + super(resId); + mPkg = pkg; + mResId = resId; + } + + @Override + public Drawable getDrawable(Context context) { + // Get the drawable from the package context + Drawable d = null; + try { + d = super.getDrawable(getPackageContext()); + } catch (Throwable t) { + Log.w(TAG, "Error creating package context" + mPkg + " id=" + mResId, t); + } + return d; + } + + private Context getPackageContext() { + if (mPackageContext == null) { + try { + mPackageContext = mContext.createPackageContext(mPkg, 0); + } catch (Throwable t) { + Log.w(TAG, "Error creating package context" + mPkg, t); + return null; + } + } + return mPackageContext; + } + } + public static class ResourceIcon extends Icon { private static final SparseArray<Icon> ICONS = new SparseArray<Icon>(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 5cc3f3f..70a27ba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -33,6 +33,7 @@ import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BluetoothController; +import cyanogenmod.app.StatusBarPanelCustomTile; import java.util.Collection; import java.util.Set; @@ -190,6 +191,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { } @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public void setToggleState(boolean state) { MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state); mController.setBluetoothEnabled(state); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 4da3cd9..f83bbf4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -33,6 +33,7 @@ import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.KeyguardMonitor; +import cyanogenmod.app.StatusBarPanelCustomTile; import java.util.LinkedHashMap; import java.util.Set; @@ -183,6 +184,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> { } @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public void setToggleState(boolean state) { // noop } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index c99d70a..426cf4b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.policy.NetworkController.MobileDataControl import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.SignalCallbackAdapter; +import cyanogenmod.app.StatusBarPanelCustomTile; /** Quick settings tile: Cellular **/ public class CellularTile extends QSTile<QSTile.SignalState> { @@ -247,6 +248,10 @@ public class CellularTile extends QSTile<QSTile.SignalState> { }; private final class CellularDetailAdapter implements DetailAdapter { + @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } @Override public int getTitle() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java new file mode 100644 index 0000000..88e5666 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java @@ -0,0 +1,177 @@ +/* + * 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 com.android.systemui.qs.tiles; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Log; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; +import cyanogenmod.app.CustomTile; +import cyanogenmod.app.StatusBarPanelCustomTile; + +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; + +public class CustomQSTile extends QSTile<QSTile.State> { + + private PendingIntent mOnClick; + private Uri mOnClickUri; + private int mCurrentUserId; + private StatusBarPanelCustomTile mTile; + private CustomQSDetailAdapter mDetailAdapter; + + public CustomQSTile(Host host, StatusBarPanelCustomTile tile) { + super(host); + refreshState(tile); + mDetailAdapter = new CustomQSDetailAdapter(); + } + + @Override + public DetailAdapter getDetailAdapter() { + return mDetailAdapter; + } + + @Override + public void setListening(boolean listening) { + } + + @Override + protected State newTileState() { + return new State(); + } + + @Override + protected void handleUserSwitch(int newUserId) { + super.handleUserSwitch(newUserId); + mCurrentUserId = newUserId; + } + + public void update(StatusBarPanelCustomTile customTile) { + refreshState(customTile); + } + + @Override + protected void handleLongClick() { + showDetail(true); + } + + @Override + protected void handleClick() { + try { + if (mOnClick != null) { + if (mOnClick.isActivity()) { + mHost.collapsePanels(); + } + mOnClick.send(); + } else if (mOnClickUri != null) { + final Intent intent = new Intent().setData(mOnClickUri); + mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId)); + } + } catch (Throwable t) { + Log.w(TAG, "Error sending click intent", t); + } + } + + @Override + protected void handleUpdateState(State state, Object arg) { + if (arg instanceof StatusBarPanelCustomTile) { + mTile = (StatusBarPanelCustomTile) arg; + } + final CustomTile customTile = mTile.getCustomTile(); + state.visible = true; + state.contentDescription = customTile.contentDescription; + state.label = customTile.label; + final int iconId = customTile.icon; + if (iconId != 0) { + final String iconPackage = mTile.getPackage(); + if (!TextUtils.isEmpty(iconPackage)) { + state.icon = new ExternalIcon(iconPackage, iconId); + } + } + mOnClick = customTile.onClick; + mOnClickUri = customTile.onClickUri; + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.DONT_TRACK_ME_BRO; + } + + private class CustomQSDetailAdapter implements DetailAdapter { + + @Override + public int getTitle() { + return R.string.quick_settings_custom_tile_detail_title; + } + + @Override + public Boolean getToggleState() { + return null; + } + + + @Override + public Intent getSettingsIntent() { + return mTile.getCustomTile().onSettingsClick; + } + + @Override + public StatusBarPanelCustomTile getCustomTile() { + return mTile; + } + + @Override + public void setToggleState(boolean state) { + // noop + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.DONT_TRACK_ME_BRO; + } + + @Override + public View createDetailView(Context context, View convertView, ViewGroup parent) { + LinearLayout rootView = (LinearLayout) LayoutInflater.from(context) + .inflate(R.layout.qs_custom_detail, parent, false); + ImageView imageView = (ImageView) rootView.findViewById(R.id.custom_qs_tile_icon); + TextView customTileTitle = (TextView) rootView.findViewById(R.id.custom_qs_tile_title); + TextView customTilePkg = (TextView) rootView + .findViewById(R.id.custom_qs_tile_package); + TextView customTileContentDesc = (TextView) rootView + .findViewById(R.id.custom_qs_tile_content_description); + + // icon is cached in state, fetch it + imageView.setImageDrawable(getState().icon.getDrawable(mContext)); + customTileTitle.setText(mTile.getCustomTile().label); + customTilePkg.setText(mTile.getPackage()); + customTileContentDesc.setText(mTile.getCustomTile().contentDescription); + return rootView; + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index afe42b9..6c40486 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -38,6 +38,7 @@ import com.android.systemui.SysUIToast; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.volume.ZenModePanel; +import cyanogenmod.app.StatusBarPanelCustomTile; /** Quick settings tile: Do not disturb **/ public class DndTile extends QSTile<QSTile.BooleanState> { @@ -249,6 +250,11 @@ public class DndTile extends QSTile<QSTile.BooleanState> { } @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public void setToggleState(boolean state) { MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state); if (!state) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index d90072e..b3e1701 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.SignalCallbackAdapter; +import cyanogenmod.app.StatusBarPanelCustomTile; import java.util.List; @@ -256,6 +257,11 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public Boolean getToggleState() { return mState.enabled; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java new file mode 100644 index 0000000..5db1f98 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java @@ -0,0 +1,67 @@ +/* + * 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 com.android.systemui.statusbar; + +import cyanogenmod.app.StatusBarPanelCustomTile; + +import android.util.ArrayMap; + +/** + * Custom tile data to keep track of created 3rd party tiles + */ +public class CustomTileData { + public static final class Entry { + public String key; + public StatusBarPanelCustomTile statusBarPanelCustomTile; + + public Entry(StatusBarPanelCustomTile sbc) { + this.key = sbc.getKey(); + } + } + + private final ArrayMap<String, Entry> mEntries = new ArrayMap<>(); + + public ArrayMap<String, Entry> getEntries() { + return mEntries; + } + + public void add(Entry entry) { + mEntries.put(entry.key, entry); + } + + public Entry remove(String key) { + Entry removed = mEntries.remove(key); + if (removed == null) return null; + return removed; + } + + public Entry get(String key) { + return mEntries.get(key); + } + + public Entry get(int i) { + return mEntries.valueAt(i); + } + + public void clear() { + mEntries.clear(); + } + + public int size() { + return mEntries.size(); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index a748aa3..f2445ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -17,12 +17,16 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -35,6 +39,7 @@ import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; import com.android.systemui.qs.tiles.ColorInversionTile; +import com.android.systemui.qs.tiles.CustomQSTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.EditTile; import com.android.systemui.qs.tiles.FlashlightTile; @@ -43,6 +48,7 @@ import com.android.systemui.qs.tiles.IntentTile; import com.android.systemui.qs.tiles.LocationTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.qs.tiles.WifiTile; +import com.android.systemui.statusbar.CustomTileData; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.FlashlightController; @@ -56,6 +62,8 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; +import cyanogenmod.app.CustomTileListenerService; +import cyanogenmod.app.StatusBarPanelCustomTile; import cyanogenmod.providers.CMSettings; import java.util.ArrayList; @@ -88,6 +96,9 @@ public class QSTileHost implements QSTile.Host, Tunable { private final UserSwitcherController mUserSwitcherController; private final KeyguardMonitor mKeyguard; private final SecurityController mSecurity; + private Handler mHandler; + + private CustomTileData mCustomTileData; private Callback mCallback; @@ -111,11 +122,22 @@ public class QSTileHost implements QSTile.Host, Tunable { mUserSwitcherController = userSwitcher; mKeyguard = keyguard; mSecurity = security; + mCustomTileData = new CustomTileData(); final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND); ht.start(); mLooper = ht.getLooper(); + mHandler = new Handler(); + + // Set up the initial notification state. + try { + mCustomTileListenerService.registerAsSystemService(mContext, + new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), + UserHandle.USER_ALL); + } catch (RemoteException e) { + Log.e(TAG, "Unable to register custom tile listener", e); + } TunerService.get(mContext).addTunableByProvider(this, CMSettings.Secure.QS_TILES, true); } @@ -164,6 +186,12 @@ public class QSTileHost implements QSTile.Host, Tunable { } @Override + public void removeCustomTile(StatusBarPanelCustomTile customTile) { + mCustomTileListenerService.removeCustomTile(customTile.getPackage(), + customTile.getTag(), customTile.getId()); + } + + @Override public void warn(String message, Throwable t) { // already logged } @@ -363,4 +391,66 @@ public class QSTileHost implements QSTile.Host, Tunable { else if (spec.equals("edit")) return R.string.quick_settings_edit_label; return 0; } + + private final CustomTileListenerService mCustomTileListenerService = + new CustomTileListenerService() { + @Override + public void onListenerConnected() { + //Connected + } + @Override + public void onCustomTilePosted(final StatusBarPanelCustomTile sbc) { + if (DEBUG) Log.d(TAG, "onCustomTilePosted: " + sbc.getCustomTile()); + mHandler.post(new Runnable() { + @Override + public void run() { + boolean isUpdate = mCustomTileData.get(sbc.getKey()) != null; + if (isUpdate) { + updateCustomTile(sbc); + } else { + addCustomTile(sbc); + } + } + }); + } + + @Override + public void onCustomTileRemoved(final StatusBarPanelCustomTile sbc) { + if (DEBUG) Log.d(TAG, "onCustomTileRemoved: " + sbc.getCustomTile()); + mHandler.post(new Runnable() { + @Override + public void run() { + removeCustomTileSysUi(sbc.getKey()); + } + }); + } + }; + + private void updateCustomTile(StatusBarPanelCustomTile sbc) { + if (mTiles.containsKey(sbc.getKey())) { + QSTile<?> tile = mTiles.get(sbc.getKey()); + if (tile instanceof CustomQSTile) { + CustomQSTile qsTile = (CustomQSTile) tile; + qsTile.update(sbc); + } + } + } + + private void addCustomTile(StatusBarPanelCustomTile sbc) { + mCustomTileData.add(new CustomTileData.Entry(sbc)); + mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc)); + if (mCallback != null) { + mCallback.onTilesChanged(); + } + } + + private void removeCustomTileSysUi(String key) { + if (mTiles.containsKey(key)) { + mTiles.remove(key); + mCustomTileData.remove(key); + if (mCallback != null) { + mCallback.onTilesChanged(); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index b8293f3..3e5152e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -75,6 +75,7 @@ import com.android.systemui.tuner.TunerService; import java.text.NumberFormat; +import cyanogenmod.app.StatusBarPanelCustomTile; import cyanogenmod.providers.CMSettings; /** @@ -749,6 +750,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL if (mEditing) { mQsPanelCallback.onShowingDetail(new QSTile.DetailAdapter() { @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public int getTitle() { return R.string.quick_settings_edit_label; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 3e8d4e9..38fb275 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -53,6 +53,7 @@ import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.statusbar.phone.SystemUIDialog; +import cyanogenmod.app.StatusBarPanelCustomTile; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -587,6 +588,11 @@ public class UserSwitcherController { } @Override + public StatusBarPanelCustomTile getCustomTile() { + return null; + } + + @Override public Boolean getToggleState() { return null; } |