Update gps status icon to be a "high power" location icon.
Move icon to right side of the screen and synchronize status with AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION. Change-Id: Iea2570501cb18be0489669fd4ea240dc63f9567a
This commit is contained in:
@ -26,7 +26,7 @@
|
|||||||
<item><xliff:g id="id">ime</xliff:g></item>
|
<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_failing</xliff:g></item>
|
||||||
<item><xliff:g id="id">sync_active</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">bluetooth</xliff:g></item>
|
||||||
<item><xliff:g id="id">nfc</xliff:g></item>
|
<item><xliff:g id="id">nfc</xliff:g></item>
|
||||||
<item><xliff:g id="id">tty</xliff:g></item>
|
<item><xliff:g id="id">tty</xliff:g></item>
|
||||||
|
@ -177,6 +177,17 @@ public class LocationManager {
|
|||||||
*/
|
*/
|
||||||
public static final String EXTRA_GPS_ENABLED = "enabled";
|
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
|
// Map from LocationListeners to their associated ListenerTransport objects
|
||||||
private HashMap<LocationListener,ListenerTransport> mListeners =
|
private HashMap<LocationListener,ListenerTransport> mListeners =
|
||||||
new HashMap<LocationListener,ListenerTransport>();
|
new HashMap<LocationListener,ListenerTransport>();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
|
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
|
||||||
|
|
||||||
<!-- Networking and telephony -->
|
<!-- Networking and telephony -->
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 814 B |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
@ -418,6 +418,9 @@
|
|||||||
<!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
|
<!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
|
||||||
<string name="gps_notification_found_text">Location set by GPS</string>
|
<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] -->
|
<!-- 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>
|
<string name="accessibility_clear_all">Clear all notifications.</string>
|
||||||
|
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.policy;
|
package com.android.systemui.statusbar.policy;
|
||||||
|
|
||||||
import android.app.INotificationManager;
|
import android.app.AppOpsManager;
|
||||||
import android.app.Notification;
|
import android.app.StatusBarManager;
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -28,35 +26,38 @@ import android.content.IntentFilter;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
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 {
|
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 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 =
|
private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
|
||||||
new ArrayList<LocationSettingsChangeCallback>();
|
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).
|
* A callback for change in location settings (the user has enabled/disabled location).
|
||||||
*/
|
*/
|
||||||
@ -74,13 +75,15 @@ public class LocationController extends BroadcastReceiver {
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
|
filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
|
||||||
filter.addAction(LocationManager.GPS_FIX_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);
|
context.registerReceiver(this, filter);
|
||||||
|
|
||||||
NotificationManager nm = (NotificationManager)context.getSystemService(
|
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||||
Context.NOTIFICATION_SERVICE);
|
mStatusBarManager
|
||||||
mNotificationService = nm.getService();
|
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
|
||||||
|
|
||||||
// Register to listen for changes to the location settings
|
// Register to listen for changes to the location settings
|
||||||
context.getContentResolver().registerContentObserver(
|
context.getContentResolver().registerContentObserver(
|
||||||
@ -94,13 +97,11 @@ public class LocationController extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Examine the current location state and initialize the status view.
|
||||||
* Add a callback to listen for changes in gps status.
|
updateActiveLocationRequests();
|
||||||
*/
|
updateAirplaneMode();
|
||||||
public void addStateChangedCallback(LocationGpsStateChangeCallback cb) {
|
refreshViews();
|
||||||
mChangeCallbacks.add(cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,76 +146,77 @@ public class LocationController extends BroadcastReceiver {
|
|||||||
return isGpsEnabled || isNetworkEnabled;
|
return isGpsEnabled || isNetworkEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads the active location requests and updates the status view if necessary.
|
||||||
|
private void updateActiveLocationRequests() {
|
||||||
|
boolean hadActiveLocationRequests = mAreActiveLocationRequests;
|
||||||
|
mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
|
||||||
|
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
|
||||||
|
refreshViews();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
final String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
|
if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
|
||||||
|
updateActiveLocationRequests();
|
||||||
boolean visible;
|
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
|
||||||
int iconId, textResId;
|
updateAirplaneMode();
|
||||||
|
|
||||||
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;
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
|
|
||||||
cb.onLocationGpsStateChanged(false, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (android.os.RemoteException ex) {
|
|
||||||
// well, it was worth a shot
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,8 +552,14 @@ public class LocationManagerService extends ILocationManager.Stub {
|
|||||||
allowHighPower = false;
|
allowHighPower = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
|
||||||
mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
|
mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
|
||||||
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user