Merge "Modify Power Widget Gps Icon To Represent Location. Instead of directly controlling gps on/off, it will control master location switch on/off." into klp-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 24ea35e..a906040 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2368,6 +2368,10 @@
<string name="location_category_recent_location_requests">Recent location requests</string>
<!-- [CHAR LIMIT=30] Location settings screen, sub category for location services -->
<string name="location_category_location_services">Location services</string>
+ <!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use-->
+ <string name="location_high_battery_use">High battery use</string>
+ <!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
+ <string name="location_low_battery_use">Low battery use</string>
<!-- [CHAR LIMIT=30] Location mode screen, screen title -->
<string name="location_mode_screen_title">Location mode</string>
<!-- [CHAR LIMIT=130] Location mode screen, description for high accuracy mode -->
diff --git a/src/com/android/settings/accessibility/AccessibilityUtils.java b/src/com/android/settings/accessibility/AccessibilityUtils.java
index 66a3ed2..7282bce 100644
--- a/src/com/android/settings/accessibility/AccessibilityUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityUtils.java
@@ -33,7 +33,8 @@
*/
class AccessibilityUtils {
/**
- * @return the set of enabled accessibility services
+ * @return the set of enabled accessibility services. If there are not services
+ * it returned the unmodifiable {@link Collections#emptySet()}.
*/
static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
final String enabledServicesSetting = Settings.Secure.getString(
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index 3059dcc..0c568f0 100644
--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -39,6 +39,8 @@
import com.android.settings.R;
import com.android.settings.accessibility.ToggleSwitch.OnBeforeCheckedChangeListener;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -81,6 +83,10 @@
Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
getActivity());
+ if (enabledServices == (Set<?>) Collections.emptySet()) {
+ enabledServices = new HashSet<ComponentName>();
+ }
+
// Determine enabled services and accessibility state.
ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
boolean accessibilityEnabled = false;
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 1f012e4..97907de 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -36,8 +36,11 @@
public class LocationSettings extends LocationSettingsBase
implements CompoundButton.OnCheckedChangeListener {
private static final String TAG = LocationSettings.class.getSimpleName();
+ /** Key for preference screen "Mode" */
private static final String KEY_LOCATION_MODE = "location_mode";
+ /** Key for preference category "Recent location requests" */
private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
+ /** Key for preference category "Location services" */
private static final String KEY_LOCATION_SERVICES = "location_services";
private Switch mSwitch;
@@ -100,6 +103,9 @@
Activity activity = getActivity();
+ RecentLocationApps recentApps = new RecentLocationApps(activity);
+ recentApps.fillAppList(mRecentLocationRequests);
+
if (activity instanceof PreferenceActivity) {
PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
// Only show the master switch when we're not in multi-pane mode, and not being used as
diff --git a/src/com/android/settings/location/RecentLocationApps.java b/src/com/android/settings/location/RecentLocationApps.java
new file mode 100644
index 0000000..113928f
--- /dev/null
+++ b/src/com/android/settings/location/RecentLocationApps.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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.settings.location;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * Retrieves the information of applications which accessed location recently.
+ */
+public class RecentLocationApps {
+ private static final String TAG = RecentLocationApps.class.getSimpleName();
+
+ private static final int RECENT_TIME_INTERVAL_MILLIS = 15 * 60 * 1000;
+
+ private Context mContext;
+ PackageManager mPackageManager;
+
+ public RecentLocationApps(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ }
+
+ /**
+ * Fills a list of applications which queried location recently within
+ * specified time.
+ */
+ public void fillAppList(PreferenceCategory container) {
+ AppOpsManager aoManager =
+ (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(
+ new int[] {
+ AppOpsManager.OP_MONITOR_LOCATION,
+ AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
+ });
+ PreferenceManager preferenceManager = container.getPreferenceManager();
+ long now = System.currentTimeMillis();
+ for (AppOpsManager.PackageOps ops : appOps) {
+ processPackageOps(now, container, preferenceManager, ops);
+ }
+ }
+
+ private void processPackageOps(
+ long now,
+ PreferenceCategory container,
+ PreferenceManager preferenceManager,
+ AppOpsManager.PackageOps ops) {
+ String packageName = ops.getPackageName();
+ List<AppOpsManager.OpEntry> entries = ops.getOps();
+ boolean highBattery = false;
+ boolean normalBattery = false;
+ for (AppOpsManager.OpEntry entry : entries) {
+ // If previous location activity is older than designated interval, ignore this app.
+ if (now - entry.getTime() <= RECENT_TIME_INTERVAL_MILLIS) {
+ switch (entry.getOp()) {
+ case AppOpsManager.OP_MONITOR_LOCATION:
+ normalBattery = true;
+ break;
+ case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
+ highBattery = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!highBattery && !normalBattery) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, packageName + " hadn't used location within the time interval.");
+ }
+ return;
+ }
+
+ try {
+ PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+ packageName, PackageManager.GET_META_DATA);
+ screen.setIcon(mPackageManager.getApplicationIcon(appInfo));
+ screen.setTitle(mPackageManager.getApplicationLabel(appInfo));
+ // if used both high and low battery within the time interval, show as "high
+ // battery"
+ if (highBattery) {
+ screen.setSummary(R.string.location_high_battery_use);
+ } else {
+ screen.setSummary(R.string.location_low_battery_use);
+ }
+ container.addPreference(screen);
+ } catch (PackageManager.NameNotFoundException e) {
+ // ignore the current app and move on to the next.
+ }
+ }
+}