diff options
Diffstat (limited to 'services')
3 files changed, 349 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 27858cb..cf1340b 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -28,7 +28,9 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; @@ -42,6 +44,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; +import android.provider.AlarmClock; import android.provider.Settings; import android.text.TextUtils; import android.text.format.DateFormat; @@ -66,6 +69,7 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; +import java.util.List; import java.util.Locale; import java.util.Random; import java.util.TimeZone; @@ -79,6 +83,13 @@ import static android.app.AlarmManager.RTC_POWEROFF_WAKEUP; import com.android.internal.util.LocalLog; +import cyanogenmod.app.CMStatusBarManager; +import cyanogenmod.app.CustomTile; + +import org.cyanogenmod.internal.util.QSUtils; +import org.cyanogenmod.internal.util.QSUtils.OnQSChanged; +import org.cyanogenmod.internal.util.QSConstants; + class AlarmManagerService extends SystemService { private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; private static final int RTC_MASK = 1 << RTC; @@ -293,6 +304,14 @@ class AlarmManagerService extends SystemService { final Constants mConstants; + private final OnQSChanged mQSListener = new OnQSChanged() { + @Override + public void onQSChanged() { + processQSChangedLocked(); + } + }; + private ContentObserver mQSObserver; + // Alarm delivery ordering bookkeeping static final int PRIO_TICK = 0; static final int PRIO_WAKEUP = 1; @@ -857,6 +876,8 @@ class AlarmManagerService extends SystemService { } publishBinderService(Context.ALARM_SERVICE, mService); + + mQSObserver = QSUtils.registerObserverForQSChanges(getContext(), mQSListener); } @Override @@ -869,6 +890,12 @@ class AlarmManagerService extends SystemService { @Override protected void finalize() throws Throwable { try { + QSUtils.unregisterObserverForQSChanges(getContext(), mQSObserver); + } catch (Exception ex) { + // Ignore + } + + try { close(mNativeData); } finally { super.finalize(); @@ -1052,6 +1079,8 @@ class AlarmManagerService extends SystemService { if (a.alarmClock != null) { mNextAlarmClockMayChange = true; + //Publish as system user + publishNextAlarmCustomTile(Process.SYSTEM_UID); } boolean needRebatch = false; @@ -1611,6 +1640,9 @@ class AlarmManagerService extends SystemService { updateNextAlarmInfoForUserLocked(userId, null); } } + + // Process dynamic custom tile + processQSChangedLocked(); } private void updateNextAlarmInfoForUserLocked(int userId, @@ -2654,6 +2686,121 @@ class AlarmManagerService extends SystemService { return bs; } + private void publishNextAlarmCustomTile(int userId) { + // This action should be performed as system + long token = Binder.clearCallingIdentity(); + try { + final UserHandle user = new UserHandle(userId); + if (!QSUtils.isQSTileEnabledForUser( + getContext(), QSConstants.DYNAMIC_TILE_NEXT_ALARM, user.getUserId(userId))) { + return; + } + + final int icon = QSUtils.getDynamicQSTileResIconId(getContext(), userId, + QSConstants.DYNAMIC_TILE_NEXT_ALARM); + final String contentDesc = QSUtils.getDynamicQSTileLabel(getContext(), userId, + QSConstants.DYNAMIC_TILE_NEXT_ALARM); + final Context resourceContext = QSUtils.getQSTileContext(getContext(), userId); + + // Create the expanded view with all the user alarms + AlarmManager.AlarmClockInfo nextAlarm = null; + CustomTile.ListExpandedStyle style = new CustomTile.ListExpandedStyle(); + ArrayList<CustomTile.ExpandedListItem> items = new ArrayList<>(); + for (Alarm alarm : getAllUserAlarmsLocked(userId)) { + if (nextAlarm == null) { + nextAlarm = alarm.alarmClock; + } + + final String pkg = alarm.operation.getCreatorPackage(); + CustomTile.ExpandedListItem item = new CustomTile.ExpandedListItem(); + item.setExpandedListItemDrawable(icon); + item.setExpandedListItemTitle(formatNextAlarm(getContext(), alarm.alarmClock, userId)); + item.setExpandedListItemSummary(getAlarmApkLabel(pkg)); + item.setExpandedListItemOnClickIntent(getCustomTilePendingIntent(user, pkg)); + items.add(item); + } + style.setListItems(items); + + // Build the custom tile + CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(getContext()); + CustomTile tile = new CustomTile.Builder(resourceContext) + .setLabel(formatNextAlarm(getContext(), nextAlarm, userId)) + .setContentDescription(contentDesc) + .setIcon(icon) + .setExpandedStyle(style) + .build(); + statusBarManager.publishTileAsUser(QSConstants.DYNAMIC_TILE_NEXT_ALARM, + AlarmManagerService.class.hashCode(), tile, user); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void unpublishNextAlarmCustomTile(int userId) { + // This action should be performed as system + long token = Binder.clearCallingIdentity(); + try { + CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(getContext()); + statusBarManager.removeTileAsUser(QSConstants.DYNAMIC_TILE_NEXT_ALARM, + AlarmManagerService.class.hashCode(), new UserHandle(userId)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private List<Alarm> getAllUserAlarmsLocked(int userId) { + List<Alarm> userAlarms = new ArrayList<>(); + synchronized (mLock) { + final int N = mAlarmBatches.size(); + for (int i = 0; i < N; i++) { + ArrayList<Alarm> alarms = mAlarmBatches.get(i).alarms; + final int M = alarms.size(); + for (int j = 0; j < M; j++) { + Alarm a = alarms.get(j); + if (a.alarmClock != null && userId == a.uid) { + userAlarms.add(a); + } + } + } + } + return userAlarms; + } + + private String getAlarmApkLabel(String pkg) { + final PackageManager pm = getContext().getPackageManager(); + ApplicationInfo ai = null; + try { + ai = pm.getApplicationInfo(pkg, 0); + } catch (final NameNotFoundException e) { + // Ignore + } + return (String) (ai != null ? pm.getApplicationLabel(ai) : pkg); + } + + private PendingIntent getCustomTilePendingIntent(UserHandle user, String pkg) { + Intent i = new Intent(AlarmClock.ACTION_SHOW_ALARMS); + i.setPackage(pkg); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return PendingIntent.getActivityAsUser(getContext(), 0, i, + PendingIntent.FLAG_UPDATE_CURRENT, null, user); + } + + private void processQSChangedLocked() { + synchronized (mLock) { + int count = mNextAlarmClockForUser.size(); + for (int i = 0; i < count; i++) { + int userId = mNextAlarmClockForUser.keyAt(i); + boolean enabled = QSUtils.isQSTileEnabledForUser( + getContext(), QSConstants.DYNAMIC_TILE_NEXT_ALARM, userId); + if (enabled) { + publishNextAlarmCustomTile(userId); + } else { + unpublishNextAlarmCustomTile(userId); + } + } + } + } + class ResultReceiver implements PendingIntent.OnFinished { public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, String resultData, Bundle resultExtras) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 6d6ca3c..e36d118 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -36,6 +36,9 @@ import com.android.server.pm.UserManagerService; import com.android.server.statusbar.StatusBarManagerService; import com.android.server.wm.WindowManagerService; +import cyanogenmod.app.CMStatusBarManager; +import cyanogenmod.app.CustomTile; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -142,6 +145,9 @@ import java.util.Locale; import cyanogenmod.providers.CMSettings; +import org.cyanogenmod.internal.util.QSUtils; +import org.cyanogenmod.internal.util.QSUtils.OnQSChanged; +import org.cyanogenmod.internal.util.QSConstants; /** * This class provides a system service that manages input methods. */ @@ -199,6 +205,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1); + private final OnQSChanged mQSListener = new OnQSChanged() { + @Override + public void onQSChanged() { + processQSChangedLocked(); + } + }; + // All known input methods. mMethodMap also serves as the global // lock for this class. final ArrayList<InputMethodInfo> mMethodList = new ArrayList<InputMethodInfo>(); @@ -949,6 +962,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } }, filter); LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl(mHandler)); + QSUtils.registerObserverForQSChanges(mContext, mQSListener); } private void resetDefaultImeLocked(Context context) { @@ -1822,6 +1836,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub com.android.internal.R.string.select_input_method, mImeSwitcherNotification.build(), UserHandle.ALL); mNotificationShown = true; + publishImeSelectorCustomTile(imi); } } else { if (mNotificationShown && mNotificationManager != null) { @@ -1831,6 +1846,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mNotificationManager.cancelAsUser(null, com.android.internal.R.string.select_input_method, UserHandle.ALL); mNotificationShown = false; + unpublishImeSelectorCustomTile(); } } } finally { @@ -3561,6 +3577,78 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private void publishImeSelectorCustomTile(InputMethodInfo imi) { + // This action should be performed as system + final int userId = UserHandle.myUserId(); + long token = Binder.clearCallingIdentity(); + try { + if (!QSUtils.isQSTileEnabledForUser( + mContext, QSConstants.DYNAMIC_TILE_IME_SELECTOR, userId)) { + return; + } + + final UserHandle user = new UserHandle(userId); + final int icon = QSUtils.getDynamicQSTileResIconId(mContext, userId, + QSConstants.DYNAMIC_TILE_IME_SELECTOR); + final String contentDesc = QSUtils.getDynamicQSTileLabel(mContext, userId, + QSConstants.DYNAMIC_TILE_IME_SELECTOR); + final Context resourceContext = QSUtils.getQSTileContext(mContext, userId); + CharSequence inputMethodName = null; + if (mCurrentSubtype != null) { + inputMethodName = mCurrentSubtype.getDisplayName(mContext, + imi.getPackageName(), imi.getServiceInfo().applicationInfo); + } + final CharSequence label = inputMethodName == null ? contentDesc : inputMethodName; + + CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(mContext); + CustomTile tile = new CustomTile.Builder(resourceContext) + .setLabel(label.toString()) + .setContentDescription(contentDesc) + .setIcon(icon) + .setOnClickIntent(mImeSwitchPendingIntent) + .build(); + statusBarManager.publishTileAsUser(QSConstants.DYNAMIC_TILE_IME_SELECTOR, + InputMethodManagerService.class.hashCode(), tile, user); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void unpublishImeSelectorCustomTile() { + // 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_IME_SELECTOR, + InputMethodManagerService.class.hashCode(), new UserHandle(userId)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void processQSChangedLocked() { + final int userId = UserHandle.myUserId(); + final boolean isIMEVisible = ((mImeWindowVis & (InputMethodService.IME_ACTIVE)) != 0) + && (mWindowManagerService.isHardKeyboardAvailable() + || (mImeWindowVis & (InputMethodService.IME_VISIBLE)) != 0); + InputMethodInfo imi = null; + synchronized (mMethodMap) { + if (mCurMethodId != null) { + imi = mMethodMap.get(mCurMethodId); + } + } + final boolean hasInputMethod = isIMEVisible && imi != null && mCurrentSubtype != null; + final boolean isEnabledForUser = QSUtils.isQSTileEnabledForUser(mContext, + QSConstants.DYNAMIC_TILE_NEXT_ALARM, userId); + boolean enabled = isEnabledForUser && hasInputMethod; + if (enabled) { + publishImeSelectorCustomTile(imi); + } else { + unpublishImeSelectorCustomTile(); + } + } + // TODO: Cache the state for each user and reset when the cached user is removed. private static class InputMethodFileManager { private static final String SYSTEM_PATH = "system"; diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 34a17a2..19e39e7 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -32,6 +32,7 @@ import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; +import android.os.Binder; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; @@ -51,8 +52,16 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.FgThread; + import cyanogenmod.providers.CMSettings; +import cyanogenmod.app.CMStatusBarManager; +import cyanogenmod.app.CustomTile; + +import org.cyanogenmod.internal.util.QSUtils; +import org.cyanogenmod.internal.util.QSUtils.OnQSChanged; +import org.cyanogenmod.internal.util.QSConstants; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -162,6 +171,13 @@ public class UsbDeviceManager { } } + private final OnQSChanged mQSListener = new OnQSChanged() { + @Override + public void onQSChanged() { + mHandler.processQSChangedLocked(); + } + }; + /* * Listens for uevent messages from the kernel to monitor the USB state */ @@ -361,11 +377,13 @@ public class UsbDeviceManager { false, adbNotificationObserver); mContentResolver.registerContentObserver( CMSettings.Secure.getUriFor(CMSettings.Secure.ADB_NOTIFY), - false, adbNotificationObserver); + false, adbNotificationObserver); // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); mUEventObserver.startObserving(ACCESSORY_START_MATCH); + + QSUtils.registerObserverForQSChanges(mContext, mQSListener); } catch (Exception e) { Slog.e(TAG, "Error initializing UsbHandler", e); } @@ -865,6 +883,12 @@ public class UsbDeviceManager { } mAdbNotificationId = id; } + + if (id > 0) { + publishAdbCustomTile(); + } else { + unpublishAdbCustomTile(); + } } private String getDefaultFunctions() { @@ -893,6 +917,95 @@ public class UsbDeviceManager { pw.println("IOException: " + e); } } + + private void publishAdbCustomTile() { + // This action should be performed as system + final int userId = UserHandle.myUserId(); + long token = Binder.clearCallingIdentity(); + try { + if (!QSUtils.isQSTileEnabledForUser( + mContext, QSConstants.DYNAMIC_TILE_ADB, userId)) { + return; + } + + final UserHandle user = new UserHandle(userId); + final int icon = QSUtils.getDynamicQSTileResIconId(mContext, userId, + QSConstants.DYNAMIC_TILE_ADB); + final String contentDesc = QSUtils.getDynamicQSTileLabel(mContext, userId, + QSConstants.DYNAMIC_TILE_ADB); + final Context resourceContext = QSUtils.getQSTileContext(mContext, userId); + + CMStatusBarManager statusBarManager = CMStatusBarManager.getInstance(mContext); + CustomTile tile = new CustomTile.Builder(resourceContext) + .setLabel(getAdbCustomTileLabel()) + .setContentDescription(contentDesc) + .setIcon(icon) + .setOnClickIntent(getCustomTilePendingIntent()) + .build(); + statusBarManager.publishTileAsUser(QSConstants.DYNAMIC_TILE_ADB, + UsbDeviceManager.class.hashCode(), tile, user); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private void unpublishAdbCustomTile() { + // 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_ADB, + UsbDeviceManager.class.hashCode(), new UserHandle(userId)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + private PendingIntent getCustomTilePendingIntent() { + Intent i = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return PendingIntent.getActivity(mContext, 0, i, PendingIntent.FLAG_UPDATE_CURRENT, null); + } + + private String getAdbCustomTileLabel() { + boolean usbAdbActive = mAdbEnabled && mConnected; + boolean netAdbActive = mAdbEnabled && + CMSettings.Secure.getInt(mContentResolver, CMSettings.Secure.ADB_PORT, -1) > 0; + + int id = 0; + if (usbAdbActive && netAdbActive) { + id = com.android.internal.R.string.adb_active_custom_tile_both; + } else if (usbAdbActive) { + id = com.android.internal.R.string.adb_active_custom_tile_usb; + } else if (netAdbActive) { + id = com.android.internal.R.string.adb_active_custom_tile_net; + } + + Resources res = mContext.getResources(); + return res.getString( + com.android.internal.R.string.adb_active_custom_tile, + res.getString(id)); + } + + private void processQSChangedLocked() { + final int userId = UserHandle.myUserId(); + boolean usbAdbActive = mAdbEnabled && mConnected; + boolean netAdbActive = mAdbEnabled && + CMSettings.Secure.getInt(mContentResolver, CMSettings.Secure.ADB_PORT, -1) > 0; + boolean notifEnabled = "1".equals(SystemProperties.get("persist.adb.notify")) + || CMSettings.Secure.getInt(mContext.getContentResolver(), + CMSettings.Secure.ADB_NOTIFY, 1) == 1; + boolean isActive = notifEnabled && (usbAdbActive || netAdbActive); + final boolean isEnabledForUser = QSUtils.isQSTileEnabledForUser(mContext, + QSConstants.DYNAMIC_TILE_ADB, userId); + boolean enabled = (userId == UserHandle.USER_OWNER) && isEnabledForUser && isActive; + if (enabled) { + publishAdbCustomTile(); + } else { + unpublishAdbCustomTile(); + } + } } /* returns the currently attached USB accessory */ |