summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java142
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java43
8 files changed, 230 insertions, 45 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
index f016dc0..9d76e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java
@@ -1477,7 +1477,10 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On
super.handleShowDetailImpl(r, show, x, y);
if (show) {
final StatusBarPanelCustomTile customTile = r.detailAdapter.getCustomTile();
- mDetailRemoveButton.setVisibility(customTile != null ? VISIBLE : GONE);
+ mDetailRemoveButton.setVisibility(customTile != null &&
+ !(customTile.getPackage().equals(mContext.getPackageName())
+ || customTile.getUid() == android.os.Process.SYSTEM_UID)
+ ? VISIBLE : GONE);
mDetailRemoveButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
index 4bc30a4..96cc51a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.ThemeConfig;
import android.net.Uri;
+import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -61,7 +62,7 @@ public class CustomQSTile extends QSTile<QSTile.State> {
public CustomQSTile(Host host, StatusBarPanelCustomTile tile) {
super(host);
- refreshState(tile);
+ mTile = tile;
}
@Override
@@ -109,6 +110,7 @@ public class CustomQSTile extends QSTile<QSTile.State> {
if (mOnClick != null) {
mOnClick.send();
} else if (mOnClickUri != null) {
+ mHost.collapsePanels();
final Intent intent = new Intent().setData(mOnClickUri);
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
}
@@ -123,9 +125,9 @@ public class CustomQSTile extends QSTile<QSTile.State> {
mTile = (StatusBarPanelCustomTile) arg;
}
final CustomTile customTile = mTile.getCustomTile();
- state.visible = true;
state.contentDescription = customTile.contentDescription;
state.label = customTile.label;
+ state.visible = true;
final int iconId = customTile.icon;
if (iconId != 0 && (customTile.remoteIcon == null)) {
final String iconPackage = mTile.getResPkg();
@@ -147,12 +149,22 @@ public class CustomQSTile extends QSTile<QSTile.State> {
return MetricsLogger.DONT_TRACK_ME_BRO;
}
+ private boolean isDynamicTile() {
+ return mTile.getPackage().equals(mContext.getPackageName())
+ || mTile.getUid() == Process.SYSTEM_UID;
+ }
+
private class CustomQSDetailAdapter implements DetailAdapter, AdapterView.OnItemClickListener,
QSDetailItemsGrid.QSDetailItemsGridAdapter.OnPseudoGriditemClickListener {
private QSDetailItemsList.QSCustomDetailListAdapter mListAdapter;
private QSDetailItemsGrid.QSDetailItemsGridAdapter mGridAdapter;
public int getTitle() {
+ if (isDynamicTile()) {
+ return mContext.getResources().getIdentifier(
+ String.format("dynamic_qs_tile_%s_label", mTile.getTag()),
+ "string", mContext.getPackageName());
+ }
return R.string.quick_settings_custom_tile_detail_title;
}
@@ -199,8 +211,12 @@ public class CustomQSTile extends QSTile<QSTile.State> {
// 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);
+ if (isDynamicTile()) {
+ customTilePkg.setText(R.string.quick_settings_dynamic_tile_detail_title);
+ } else {
+ customTilePkg.setText(mTile.getPackage());
+ customTileContentDesc.setText(mTile.getCustomTile().contentDescription);
+ }
} else {
switch (mExpandedStyle.getStyle()) {
case CustomTile.ExpandedStyle.GRID_STYLE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
index 5db1f98..4be7292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java
@@ -25,11 +25,12 @@ import android.util.ArrayMap;
*/
public class CustomTileData {
public static final class Entry {
- public String key;
- public StatusBarPanelCustomTile statusBarPanelCustomTile;
+ public final String key;
+ public final StatusBarPanelCustomTile sbc;
public Entry(StatusBarPanelCustomTile sbc) {
this.key = sbc.getKey();
+ this.sbc = sbc;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index bcf1c2f..3987a35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -424,6 +424,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onAnimationEnd(Animator animation) {
mQsSizeChangeAnimator = null;
+ mQsContainer.setHeightOverride(-1);
}
});
mQsSizeChangeAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index ee291f5..9c1ae95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -20,15 +20,21 @@ import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -51,8 +57,16 @@ import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.SuController;
+import cyanogenmod.app.CMStatusBarManager;
+import cyanogenmod.app.CustomTile;
import cyanogenmod.providers.CMSettings;
+import org.cyanogenmod.internal.util.QSUtils;
+import org.cyanogenmod.internal.util.QSUtils.OnQSChanged;
+import org.cyanogenmod.internal.util.QSConstants;
+
+import java.util.ArrayList;
+
/**
* This class contains all of the policy about which icons are installed in the status
* bar at boot time. It goes through the normal API for icons, even though it probably
@@ -126,6 +140,13 @@ public class PhoneStatusBarPolicy implements Callback {
}
};
+ private final OnQSChanged mQSListener = new OnQSChanged() {
+ @Override
+ public void onQSChanged() {
+ processQSChangedLocked();
+ }
+ };
+
public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
UserInfoController userInfoController, BluetoothController bluetooth, SuController su) {
mContext = context;
@@ -198,6 +219,8 @@ public class PhoneStatusBarPolicy implements Callback {
mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
mContext.getString(R.string.accessibility_managed_profile));
mService.setIconVisibility(SLOT_MANAGED_PROFILE, false);
+
+ QSUtils.registerObserverForQSChanges(mContext, mQSListener);
}
private ContentObserver mAlarmIconObserver = new ContentObserver(null) {
@@ -448,6 +471,12 @@ public class PhoneStatusBarPolicy implements Callback {
private void updateSu() {
mService.setIconVisibility(SLOT_SU, mSuController.hasActiveSessions());
+ final int userId = UserHandle.myUserId();
+ if (isSuEnabledForUser(userId)) {
+ publishSuCustomTile();
+ } else {
+ unpublishSuCustomTile();
+ }
}
private final CastController.Callback mCastCallback = new CastController.Callback() {
@@ -479,4 +508,117 @@ public class PhoneStatusBarPolicy implements Callback {
}
};
+ private void publishSuCustomTile() {
+ // This action should be performed as system
+ final int userId = UserHandle.myUserId();
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (!QSUtils.isQSTileEnabledForUser(
+ mContext, QSConstants.DYNAMIC_TILE_SU, userId)) {
+ return;
+ }
+
+ final UserHandle user = new UserHandle(userId);
+ final int icon = QSUtils.getDynamicQSTileResIconId(mContext, userId,
+ QSConstants.DYNAMIC_TILE_SU);
+ final String contentDesc = QSUtils.getDynamicQSTileLabel(mContext, userId,
+ QSConstants.DYNAMIC_TILE_SU);
+ final Context resourceContext = QSUtils.getQSTileContext(mContext, userId);
+
+ CustomTile.ListExpandedStyle style = new CustomTile.ListExpandedStyle();
+ ArrayList<CustomTile.ExpandedListItem> items = new ArrayList<>();
+ for (String pkg : mSuController.getPackageNamesWithActiveSuSessions()) {
+ CustomTile.ExpandedListItem item = new CustomTile.ExpandedListItem();
+ int appIconIdentifier = getActiveSuApkDrawableId(pkg);
+ if (appIconIdentifier != -1) {
+ item.setExpandedListItemDrawable(appIconIdentifier);
+ } else {
+ item.setExpandedListItemDrawable(icon);
+ }
+ item.setExpandedListItemTitle(getActiveSuApkLabel(pkg));
+ item.setExpandedListItemSummary(pkg);
+ item.setExpandedListItemOnClickIntent(getCustomTilePendingIntent(pkg));
+ items.add(item);
+ }
+ style.setListItems(items);
+
+ CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(mContext);
+ CustomTile tile = new CustomTile.Builder(resourceContext)
+ .setLabel(contentDesc)
+ .setContentDescription(contentDesc)
+ .setIcon(icon)
+ .setOnSettingsClickIntent(getCustomTileSettingsIntent())
+ .setExpandedStyle(style)
+ .build();
+ statusBarManager.publishTileAsUser(QSConstants.DYNAMIC_TILE_SU,
+ PhoneStatusBarPolicy.class.hashCode(), tile, user);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void unpublishSuCustomTile() {
+ // This action should be performed as system
+ final int userId = UserHandle.myUserId();
+ long token = Binder.clearCallingIdentity();
+ try {
+ CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(mContext);
+ statusBarManager.removeTileAsUser(QSConstants.DYNAMIC_TILE_SU,
+ PhoneStatusBarPolicy.class.hashCode(), new UserHandle(userId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private PendingIntent getCustomTilePendingIntent(String pkg) {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.setPackage(pkg);
+ i.addCategory(Intent.CATEGORY_LAUNCHER);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private Intent getCustomTileSettingsIntent() {
+ Intent i = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return i;
+ }
+
+ private String getActiveSuApkLabel(String pkg) {
+ final PackageManager pm = mContext.getPackageManager();
+ ApplicationInfo ai = null;
+ try {
+ ai = pm.getApplicationInfo(pkg, 0);
+ } catch (final NameNotFoundException e) {
+ // Ignore
+ }
+ return (String) (ai != null ? pm.getApplicationLabel(ai) : pkg);
+ }
+
+ private int getActiveSuApkDrawableId(String pkg) {
+ final PackageManager pm = mContext.getPackageManager();
+ ApplicationInfo ai;
+ try {
+ ai = pm.getApplicationInfo(pkg, 0);
+ } catch (final NameNotFoundException e) {
+ return -1;
+ }
+ return ai.icon;
+ }
+
+ private boolean isSuEnabledForUser(int userId) {
+ final boolean hasSuAccess = mSuController.hasActiveSessions();
+ final boolean isEnabledForUser = QSUtils.isQSTileEnabledForUser(mContext,
+ QSConstants.DYNAMIC_TILE_SU, userId);
+ return (userId == UserHandle.USER_OWNER) && isEnabledForUser && hasSuAccess;
+ }
+
+ private void processQSChangedLocked() {
+ final int userId = UserHandle.myUserId();
+ if (isSuEnabledForUser(userId)) {
+ publishSuCustomTile();
+ } else {
+ unpublishSuCustomTile();
+ }
+ }
}
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 eff9b0a..be6f143 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -289,6 +289,7 @@ public class QSTileHost implements QSTile.Host, Tunable {
}
if (DEBUG) Log.d(TAG, "Recreating tiles");
final List<String> tileSpecs = loadTileSpecs(newValue);
+ removeUnusedDynamicTiles(tileSpecs);
if (tileSpecs.equals(mTileSpecs)) return;
for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
if (!tileSpecs.contains(tile.getKey())) {
@@ -318,6 +319,23 @@ public class QSTileHost implements QSTile.Host, Tunable {
}
}
+ private void removeUnusedDynamicTiles(List<String> tileSpecs) {
+ List<CustomTileData.Entry> tilesToRemove = new ArrayList<>();
+ for (CustomTileData.Entry entry : mCustomTileData.getEntries().values()) {
+ if (entry.sbc.getPackage().equals(mContext.getPackageName())
+ || entry.sbc.getUid() == Process.SYSTEM_UID) {
+ if (!tileSpecs.contains(entry.sbc.getTag())) {
+ tilesToRemove.add(entry);
+ }
+ }
+ }
+
+ for (CustomTileData.Entry entry : tilesToRemove) {
+ mCustomTileData.remove(entry.key);
+ removeCustomTile(entry.sbc);
+ }
+ }
+
@Override
public void goToSettingsPage() {
if (mCallback != null) {
@@ -429,29 +447,35 @@ public class QSTileHost implements QSTile.Host, Tunable {
}
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);
+ synchronized (mTiles) {
+ if (mTiles.containsKey(sbc.getKey())) {
+ QSTile<?> tile = mTiles.get(sbc.getKey());
+ if (tile instanceof CustomQSTile) {
+ CustomQSTile qsTile = (CustomQSTile) tile;
+ qsTile.update(sbc);
+ }
}
}
}
void addCustomTile(StatusBarPanelCustomTile sbc) {
- mCustomTileData.add(new CustomTileData.Entry(sbc));
- mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc));
- if (mCallback != null) {
- mCallback.onTilesChanged();
+ synchronized (mTiles) {
+ mCustomTileData.add(new CustomTileData.Entry(sbc));
+ mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc));
+ if (mCallback != null) {
+ mCallback.onTilesChanged();
+ }
}
}
void removeCustomTileSysUi(String key) {
- if (mTiles.containsKey(key)) {
- mTiles.remove(key);
- mCustomTileData.remove(key);
- if (mCallback != null) {
- mCallback.onTilesChanged();
+ synchronized (mTiles) {
+ 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/policy/SuController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java
index 5f1e52e..de67261 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuController.java
@@ -16,10 +16,13 @@
package com.android.systemui.statusbar.policy;
+import java.util.List;
+
public interface SuController {
void addCallback(Callback callback);
void removeCallback(Callback callback);
boolean hasActiveSessions();
+ List<String> getPackageNamesWithActiveSuSessions();
public interface Callback {
void onSuSessionsChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java
index 1ba334a..c663bab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SuControllerImpl.java
@@ -16,22 +16,15 @@
package com.android.systemui.statusbar.policy;
-import android.app.ActivityManager;
import android.app.AppOpsManager;
-import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
import android.util.Log;
-import com.android.systemui.R;
-
import java.util.ArrayList;
import java.util.List;
@@ -45,15 +38,11 @@ public class SuControllerImpl implements SuController {
private ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
- private Context mContext;
-
private AppOpsManager mAppOpsManager;
- private boolean mHasActiveSuSessions;
+ private List<String> mActiveSuSessions = new ArrayList<>();
public SuControllerImpl(Context context) {
- mContext = context;
-
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
IntentFilter intentFilter = new IntentFilter();
@@ -85,7 +74,9 @@ public class SuControllerImpl implements SuController {
@Override
public boolean hasActiveSessions() {
- return mHasActiveSuSessions;
+ synchronized (mActiveSuSessions) {
+ return mActiveSuSessions.size() > 0;
+ }
}
private void fireCallback(Callback callback) {
@@ -98,10 +89,10 @@ public class SuControllerImpl implements SuController {
}
}
- /**
- * Returns true if a su session is active
- */
- private boolean hasActiveSuSessions() {
+ // Return the list of package names that currently have an active su session
+ @Override
+ public List<String> getPackageNamesWithActiveSuSessions() {
+ List<String> packageNames = new ArrayList<>();
List<AppOpsManager.PackageOps> packages
= mAppOpsManager.getPackagesForOps(mSuOpArray);
// AppOpsManager can return null when there is no requested data.
@@ -116,7 +107,8 @@ public class SuControllerImpl implements SuController {
AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
if (opEntry.getOp() == AppOpsManager.OP_SU) {
if (opEntry.isRunning()) {
- return true;
+ packageNames.add(packageOp.getPackageName());
+ break;
}
}
}
@@ -124,14 +116,17 @@ public class SuControllerImpl implements SuController {
}
}
- return false;
+ return packageNames;
}
- private void updateActiveSuSessions() {
- boolean hadActiveSuSessions = mHasActiveSuSessions;
- mHasActiveSuSessions = hasActiveSuSessions();
- if (mHasActiveSuSessions != hadActiveSuSessions) {
- fireCallbacks();
+ private synchronized void updateActiveSuSessions() {
+ List<String> newList = getPackageNamesWithActiveSuSessions();
+ synchronized (mActiveSuSessions) {
+ if (!newList.equals(mActiveSuSessions)) {
+ mActiveSuSessions.clear();
+ mActiveSuSessions.addAll(newList);
+ fireCallbacks();
+ }
}
}
}