diff options
-rw-r--r-- | core/res/res/values/config.xml | 2 | ||||
-rw-r--r-- | location/java/android/location/LocationManager.java | 11 | ||||
-rw-r--r-- | packages/SystemUI/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png | bin | 0 -> 1222 bytes | |||
-rw-r--r-- | packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png | bin | 0 -> 814 bytes | |||
-rw-r--r-- | packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png | bin | 0 -> 1638 bytes | |||
-rw-r--r-- | packages/SystemUI/res/values/strings.xml | 3 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java | 190 | ||||
-rw-r--r-- | services/java/com/android/server/LocationManagerService.java | 6 |
9 files changed, 118 insertions, 95 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b9840e2..0908f36 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -26,7 +26,7 @@ <item><xliff:g id="id">ime</xliff:g></item> <item><xliff:g id="id">sync_failing</xliff:g></item> <item><xliff:g id="id">sync_active</xliff:g></item> - <item><xliff:g id="id">gps</xliff:g></item> + <item><xliff:g id="id">location</xliff:g></item> <item><xliff:g id="id">bluetooth</xliff:g></item> <item><xliff:g id="id">nfc</xliff:g></item> <item><xliff:g id="id">tty</xliff:g></item> diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 989178a..e5f1cf5 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -177,6 +177,17 @@ public class LocationManager { */ public static final String EXTRA_GPS_ENABLED = "enabled"; + /** + * Broadcast intent action indicating that a high power location requests + * has either started or stopped being active. The current state of + * active location requests should be read from AppOpsManager using + * {@code OP_MONITOR_HIGH_POWER_LOCATION}. + * + * @hide + */ + public static final String HIGH_POWER_REQUEST_CHANGE_ACTION = + "android.location.HIGH_POWER_REQUEST_CHANGE"; + // Map from LocationListeners to their associated ListenerTransport objects private HashMap<LocationListener,ListenerTransport> mListeners = new HashMap<LocationListener,ListenerTransport>(); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2267372..5e198a2 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <!-- Networking and telephony --> <uses-permission android:name="android.permission.BLUETOOTH" /> diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..657a612 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..80fc24b --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png Binary files differnew file mode 100644 index 0000000..fd8ad64 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 0073e60..33a85c3 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -418,6 +418,9 @@ <!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] --> <string name="gps_notification_found_text">Location set by GPS</string> + <!-- Accessibility text describing the presence of active location requests by one or more apps --> + <string name="accessibility_location_active">Location requests active</string> + <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_clear_all">Clear all notifications.</string> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java index 3f8043d..91ddf0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java @@ -16,10 +16,8 @@ package com.android.systemui.statusbar.policy; -import android.app.INotificationManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; +import android.app.AppOpsManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -28,36 +26,39 @@ import android.content.IntentFilter; import android.database.ContentObserver; import android.location.LocationManager; import android.os.Handler; -import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import com.android.systemui.R; import java.util.ArrayList; +import java.util.List; +/** + * A controller to manage changes of location related states and update the views accordingly. + */ public class LocationController extends BroadcastReceiver { - private static final String TAG = "StatusBar.LocationController"; + // The name of the placeholder corresponding to the location request status icon. + // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml. + private static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location"; + private static final int LOCATION_STATUS_ICON_ID + = R.drawable.stat_sys_device_access_location_found; - private static final int GPS_NOTIFICATION_ID = 374203-122084; + private static final int[] mHighPowerRequestAppOpArray + = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION}; private Context mContext; - private INotificationManager mNotificationService; + private AppOpsManager mAppOpsManager; + private StatusBarManager mStatusBarManager; + + private boolean mAreActiveLocationRequests; + private boolean mIsAirplaneMode; - private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks = - new ArrayList<LocationGpsStateChangeCallback>(); private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks = new ArrayList<LocationSettingsChangeCallback>(); /** - * A callback for change in gps status (enabled/disabled, have lock, etc). - */ - public interface LocationGpsStateChangeCallback { - public void onLocationGpsStateChanged(boolean inUse, String description); - } - - /** * A callback for change in location settings (the user has enabled/disabled location). */ public interface LocationSettingsChangeCallback { @@ -74,13 +75,15 @@ public class LocationController extends BroadcastReceiver { mContext = context; IntentFilter filter = new IntentFilter(); - filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION); - filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION); + filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); + // Listen for a change in the airplane mode setting so we can defensively turn off the + // high power location icon when radios are disabled. + filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); context.registerReceiver(this, filter); - NotificationManager nm = (NotificationManager)context.getSystemService( - Context.NOTIFICATION_SERVICE); - mNotificationService = nm.getService(); + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mStatusBarManager + = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); // Register to listen for changes to the location settings context.getContentResolver().registerContentObserver( @@ -94,13 +97,11 @@ public class LocationController extends BroadcastReceiver { } } }); - } - /** - * Add a callback to listen for changes in gps status. - */ - public void addStateChangedCallback(LocationGpsStateChangeCallback cb) { - mChangeCallbacks.add(cb); + // Examine the current location state and initialize the status view. + updateActiveLocationRequests(); + updateAirplaneMode(); + refreshViews(); } /** @@ -145,76 +146,77 @@ public class LocationController extends BroadcastReceiver { return isGpsEnabled || isNetworkEnabled; } - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false); - - boolean visible; - int iconId, textResId; - - if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) { - // GPS is getting fixes - iconId = com.android.internal.R.drawable.stat_sys_gps_on; - textResId = R.string.gps_notification_found_text; - visible = true; - } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) { - // GPS is off - visible = false; - iconId = textResId = 0; + /** + * Returns true if there currently exist active high power location requests. + */ + private boolean areActiveHighPowerLocationRequests() { + List<AppOpsManager.PackageOps> packages + = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray); + // AppOpsManager can return null when there is no requested data. + if (packages != null) { + final int numPackages = packages.size(); + for (int packageInd = 0; packageInd < numPackages; packageInd++) { + AppOpsManager.PackageOps packageOp = packages.get(packageInd); + List<AppOpsManager.OpEntry> opEntries = packageOp.getOps(); + if (opEntries != null) { + final int numOps = opEntries.size(); + for (int opInd = 0; opInd < numOps; opInd++) { + AppOpsManager.OpEntry opEntry = opEntries.get(opInd); + // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because + // of the mHighPowerRequestAppOpArray filter, but checking defensively. + if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) { + if (opEntry.isRunning()) { + return true; + } + } + } + } + } + } + + return false; + } + + // Updates the status view based on the current state of location requests and airplane mode. + private void refreshViews() { + // The airplane mode check is defensive - there shouldn't be any active high power + // location requests when airplane mode is on. + if (!mIsAirplaneMode && mAreActiveLocationRequests) { + mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0, + mContext.getString(R.string.accessibility_location_active)); } else { - // GPS is on, but not receiving fixes - iconId = R.drawable.stat_sys_gps_acquiring_anim; - textResId = R.string.gps_notification_searching_text; - visible = true; + mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER); } + } - try { - if (visible) { - Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0, - gpsIntent, 0, null, UserHandle.CURRENT); - String text = mContext.getText(textResId).toString(); - - Notification n = new Notification.Builder(mContext) - .setSmallIcon(iconId) - .setContentTitle(text) - .setOngoing(true) - .setContentIntent(pendingIntent) - .getNotification(); - - // Notification.Builder will helpfully fill these out for you no matter what you do - n.tickerView = null; - n.tickerText = null; - - n.priority = Notification.PRIORITY_HIGH; - - int[] idOut = new int[1]; - mNotificationService.enqueueNotificationWithTag( - mContext.getPackageName(), mContext.getBasePackageName(), - null, - GPS_NOTIFICATION_ID, - n, - idOut, - UserHandle.USER_ALL); - - for (LocationGpsStateChangeCallback cb : mChangeCallbacks) { - cb.onLocationGpsStateChanged(true, text); - } - } else { - mNotificationService.cancelNotificationWithTag( - mContext.getPackageName(), null, - GPS_NOTIFICATION_ID, UserHandle.USER_ALL); + // Reads the active location requests and updates the status view if necessary. + private void updateActiveLocationRequests() { + boolean hadActiveLocationRequests = mAreActiveLocationRequests; + mAreActiveLocationRequests = areActiveHighPowerLocationRequests(); + if (mAreActiveLocationRequests != hadActiveLocationRequests) { + refreshViews(); + } + } - for (LocationGpsStateChangeCallback cb : mChangeCallbacks) { - cb.onLocationGpsStateChanged(false, null); - } - } - } catch (android.os.RemoteException ex) { - // well, it was worth a shot + // Reads the airplane mode setting and updates the status view if necessary. + private void updateAirplaneMode() { + boolean wasAirplaneMode = mIsAirplaneMode; + // TODO This probably warrants a utility method in Settings.java. + mIsAirplaneMode = (Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1); + if (mIsAirplaneMode != wasAirplaneMode) { + refreshViews(); } } -} + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) { + updateActiveLocationRequests(); + } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { + updateAirplaneMode(); + } + } +} diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index cde84dc..6175268 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -552,8 +552,14 @@ public class LocationManagerService extends ILocationManager.Stub { allowHighPower = false; } } + boolean wasHighPowerMonitoring = mOpHighPowerMonitoring; mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring, AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION); + if (mOpHighPowerMonitoring != wasHighPowerMonitoring) { + // send an intent to notify that a high power request has been added/removed. + Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } } /** |