OSDN Git Service

Make Location Settings multiprofile aware
authorZoltan Szatmary-Ban <szatmz@google.com>
Wed, 15 Oct 2014 10:35:55 +0000 (11:35 +0100)
committerZoltan Szatmary-Ban <szatmz@google.com>
Fri, 5 Dec 2014 19:40:59 +0000 (19:40 +0000)
Injected location services and location access status are shown
for managed profiles on Settings > Location

Bug: 18602878
Change-Id: Ic6232f3dc03d9675b90fbfd0163fe5bae4bd13c6

res/xml/location_settings.xml
src/com/android/settings/location/DimmableIconPreference.java
src/com/android/settings/location/InjectedSetting.java
src/com/android/settings/location/LocationSettings.java
src/com/android/settings/location/RecentLocationApps.java
src/com/android/settings/location/SettingsInjector.java

index 994ddf1..2cd86f5 100644 (file)
             settings:keywords="@string/keywords_location_mode"
             android:summary="@string/location_mode_location_off_title" />
 
+        <!-- This preference category gets removed if there is no managed profile -->
+        <PreferenceCategory
+            android:key="managed_profile_location_category"
+            android:title="@string/managed_profile_location_category">
+
+            <Preference
+                android:key="managed_profile_location_switch"
+                android:title="@string/managed_profile_location_switch_title"
+                android:summary="@string/managed_profile_location_switch_lockdown"
+                android:persistent="false"
+                android:enabled="false"
+                android:selectable="false" />
+
+        </PreferenceCategory>
+
         <PreferenceCategory
             android:key="recent_location_requests"
             android:title="@string/location_category_recent_location_requests" />
index acde1c1..f785992 100644 (file)
 
 package com.android.settings.location;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.preference.Preference;
+import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
 
 /**
  * A preference item that can dim the icon when it's disabled, either directly or because its parent
@@ -29,16 +33,23 @@ public class DimmableIconPreference extends Preference {
     private static final int ICON_ALPHA_ENABLED = 255;
     private static final int ICON_ALPHA_DISABLED = 102;
 
-    public DimmableIconPreference(Context context, AttributeSet attrs, int defStyle) {
+    private final CharSequence mContentDescription;
+
+    public DimmableIconPreference(Context context, AttributeSet attrs, int defStyle,
+            @Nullable CharSequence contentDescription) {
         super(context, attrs, defStyle);
+        mContentDescription = contentDescription;
     }
 
-    public DimmableIconPreference(Context context, AttributeSet attrs) {
+    public DimmableIconPreference(Context context, AttributeSet attrs,
+            @Nullable CharSequence contentDescription) {
         super(context, attrs);
+        mContentDescription = contentDescription;
     }
 
-    public DimmableIconPreference(Context context) {
+    public DimmableIconPreference(Context context, @Nullable CharSequence contentDescription) {
         super(context);
+        mContentDescription = contentDescription;
     }
 
     private void dimIcon(boolean dimmed) {
@@ -60,4 +71,13 @@ public class DimmableIconPreference extends Preference {
         dimIcon(!enabled);
         super.setEnabled(enabled);
     }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        if (!TextUtils.isEmpty(mContentDescription)) {
+            final TextView titleView = (TextView) view.findViewById(android.R.id.title);
+            titleView.setContentDescription(mContentDescription);
+        }
+    }
 }
index 5f4440a..bb009b9 100644 (file)
@@ -19,6 +19,7 @@ package com.android.settings.location;
 import android.content.Intent;
 import android.text.TextUtils;
 import android.util.Log;
+import android.os.UserHandle;
 import com.android.internal.annotations.Immutable;
 import com.android.internal.util.Preconditions;
 
@@ -53,17 +54,23 @@ class InjectedSetting {
     public final int iconId;
 
     /**
+     * The user/profile associated with this setting (e.g. managed profile)
+     */
+    public final UserHandle mUserHandle;
+
+    /**
      * The activity to launch to allow the user to modify the settings value. Assumed to be in the
      * {@link #packageName} package.
      */
     public final String settingsActivity;
 
     private InjectedSetting(String packageName, String className,
-            String title, int iconId, String settingsActivity) {
+            String title, int iconId, UserHandle userHandle, String settingsActivity) {
         this.packageName = Preconditions.checkNotNull(packageName, "packageName");
         this.className = Preconditions.checkNotNull(className, "className");
         this.title = Preconditions.checkNotNull(title, "title");
         this.iconId = iconId;
+        this.mUserHandle = userHandle;
         this.settingsActivity = Preconditions.checkNotNull(settingsActivity);
     }
 
@@ -71,7 +78,7 @@ class InjectedSetting {
      * Returns a new instance, or null.
      */
     public static InjectedSetting newInstance(String packageName, String className,
-            String title, int iconId, String settingsActivity) {
+            String title, int iconId, UserHandle userHandle, String settingsActivity) {
         if (packageName == null || className == null ||
                 TextUtils.isEmpty(title) || TextUtils.isEmpty(settingsActivity)) {
             if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
@@ -81,7 +88,8 @@ class InjectedSetting {
             }
             return null;
         }
-        return new InjectedSetting(packageName, className, title, iconId, settingsActivity);
+        return new InjectedSetting(packageName, className, title, iconId, userHandle,
+                settingsActivity);
     }
 
     @Override
@@ -91,6 +99,7 @@ class InjectedSetting {
                 ", mClassName='" + className + '\'' +
                 ", label=" + title +
                 ", iconId=" + iconId +
+                ", userId=" + mUserHandle.getIdentifier() +
                 ", settingsActivity='" + settingsActivity + '\'' +
                 '}';
     }
@@ -113,6 +122,7 @@ class InjectedSetting {
 
         return packageName.equals(that.packageName) && className.equals(that.className)
                 && title.equals(that.title) && iconId == that.iconId
+                && mUserHandle.equals(that.mUserHandle)
                 && settingsActivity.equals(that.settingsActivity);
     }
 
@@ -122,6 +132,7 @@ class InjectedSetting {
         result = 31 * result + className.hashCode();
         result = 31 * result + title.hashCode();
         result = 31 * result + iconId;
+        result = 31 * result + mUserHandle.hashCode();
         result = 31 * result + settingsActivity.hashCode();
         return result;
     }
index c0a13c1..ba5cd92 100644 (file)
@@ -21,16 +21,22 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.location.SettingInjectorService;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
 import android.util.Log;
 import android.widget.Switch;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.widget.SwitchBar;
 
 import java.util.Collections;
@@ -45,6 +51,17 @@ public class LocationSettings extends LocationSettingsBase
 
     private static final String TAG = "LocationSettings";
 
+    /**
+     * Key for managed profile location preference category. Category is shown only
+     * if there is a managed profile
+     */
+    private static final String KEY_MANAGED_PROFILE_CATEGORY = "managed_profile_location_category";
+    /**
+     * Key for managed profile location preference. Note it used to be a switch pref and we had to
+     * keep the key as strings had been submitted for string freeze before the decision to
+     * demote this to a simple preference was made. TODO: Candidate for refactoring.
+     */
+    private static final String KEY_MANAGED_PROFILE_PREFERENCE = "managed_profile_location_switch";
     /** Key for preference screen "Mode" */
     private static final String KEY_LOCATION_MODE = "location_mode";
     /** Key for preference category "Recent location requests" */
@@ -55,17 +72,21 @@ public class LocationSettings extends LocationSettingsBase
     private SwitchBar mSwitchBar;
     private Switch mSwitch;
     private boolean mValidListener = false;
+    private UserHandle mManagedProfile;
+    private Preference mManagedProfilePreference;
     private Preference mLocationMode;
     private PreferenceCategory mCategoryRecentLocationRequests;
     /** Receives UPDATE_INTENT  */
     private BroadcastReceiver mReceiver;
     private SettingsInjector injector;
+    private UserManager mUm;
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         final SettingsActivity activity = (SettingsActivity) getActivity();
+        mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
 
         mSwitchBar = activity.getSwitchBar();
         mSwitch = mSwitchBar.getSwitch();
@@ -127,6 +148,7 @@ public class LocationSettings extends LocationSettingsBase
         addPreferencesFromResource(R.xml.location_settings);
         root = getPreferenceScreen();
 
+        setupManagedProfileCategory(root);
         mLocationMode = root.findPreference(KEY_LOCATION_MODE);
         mLocationMode.setOnPreferenceClickListener(
                 new Preference.OnPreferenceClickListener() {
@@ -155,12 +177,42 @@ public class LocationSettings extends LocationSettingsBase
             mCategoryRecentLocationRequests.addPreference(banner);
         }
 
-        addLocationServices(activity, root);
+        boolean lockdownOnLocationAccess = false;
+        // Checking if device policy has put a location access lock-down on the managed
+        // profile. If managed profile has lock-down on location access then its
+        // injected location services must not be shown.
+        if (mManagedProfile != null
+                && mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
+            lockdownOnLocationAccess = true;
+        }
+        addLocationServices(activity, root, lockdownOnLocationAccess);
 
         refreshLocationMode();
         return root;
     }
 
+    private void setupManagedProfileCategory(PreferenceScreen root) {
+        // Looking for a managed profile. If there are no managed profiles then we are removing the
+        // managed profile category.
+        mManagedProfile = Utils.getManagedProfile(mUm);
+        if (mManagedProfile == null) {
+            // There is no managed profile
+            root.removePreference(root.findPreference(KEY_MANAGED_PROFILE_CATEGORY));
+            mManagedProfilePreference = null;
+        } else {
+            mManagedProfilePreference = root.findPreference(KEY_MANAGED_PROFILE_PREFERENCE);
+            mManagedProfilePreference.setOnPreferenceClickListener(null);
+        }
+    }
+
+    private void changeManagedProfileLocationAccessStatus(boolean enabled, int summaryResId) {
+        if (mManagedProfilePreference == null) {
+            return;
+        }
+        mManagedProfilePreference.setEnabled(enabled);
+        mManagedProfilePreference.setSummary(summaryResId);
+    }
+
     /**
      * Add the settings injected by external apps into the "App Settings" category. Hides the
      * category if there are no injected settings.
@@ -168,11 +220,15 @@ public class LocationSettings extends LocationSettingsBase
      * Reloads the settings whenever receives
      * {@link SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED}.
      */
-    private void addLocationServices(Context context, PreferenceScreen root) {
+    private void addLocationServices(Context context, PreferenceScreen root,
+            boolean lockdownOnLocationAccess) {
         PreferenceCategory categoryLocationServices =
                 (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
         injector = new SettingsInjector(context);
-        List<Preference> locationServices = injector.getInjectedSettings();
+        // If location access is locked down by device policy then we only show injected settings
+        // for the primary profile.
+        List<Preference> locationServices = injector.getInjectedSettings(lockdownOnLocationAccess ?
+                UserHandle.myUserId() : UserHandle.USER_CURRENT);
 
         mReceiver = new BroadcastReceiver() {
             @Override
@@ -223,7 +279,7 @@ public class LocationSettings extends LocationSettingsBase
         // Restricted user can't change the location mode, so disable the master switch. But in some
         // corner cases, the location might still be enabled. In such case the master switch should
         // be disabled but checked.
-        boolean enabled = (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF);
+        final boolean enabled = (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF);
         // Disable the whole switch bar instead of the switch itself. If we disabled the switch
         // only, it would be re-enabled again if the switch bar is not disabled.
         mSwitchBar.setEnabled(!restricted);
@@ -240,6 +296,20 @@ public class LocationSettings extends LocationSettingsBase
                 mSwitchBar.addOnSwitchChangeListener(this);
             }
         }
+
+        if (mManagedProfilePreference != null) {
+            if (mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
+                changeManagedProfileLocationAccessStatus(false,
+                        R.string.managed_profile_location_switch_lockdown);
+            } else {
+                if (enabled) {
+                    changeManagedProfileLocationAccessStatus(true, R.string.switch_on_text);
+                } else {
+                    changeManagedProfileLocationAccessStatus(false, R.string.switch_off_text);
+                }
+            }
+        }
+
         // As a safety measure, also reloads on location mode change to ensure the settings are
         // up-to-date even if an affected app doesn't send the setting changed broadcast.
         injector.reloadStatusMessages();
index 7e99725..9f2b8ab 100644 (file)
@@ -77,35 +77,13 @@ public class RecentLocationApps {
         }
     }
 
-    /**
-     * Subclass of {@link Preference} to intercept views and allow content description to be set on
-     * them for accessibility purposes.
-     */
-    private static class AccessiblePreference extends DimmableIconPreference {
-        public CharSequence mContentDescription;
-
-        public AccessiblePreference(Context context, CharSequence contentDescription) {
-            super(context);
-            mContentDescription = contentDescription;
-        }
-
-        @Override
-        protected void onBindView(View view) {
-            super.onBindView(view);
-            if (mContentDescription != null) {
-                final TextView titleView = (TextView) view.findViewById(android.R.id.title);
-                titleView.setContentDescription(mContentDescription);
-            }
-        }
-    }
-
-    private AccessiblePreference createRecentLocationEntry(
+    private DimmableIconPreference createRecentLocationEntry(
             Drawable icon,
             CharSequence label,
             boolean isHighBattery,
             CharSequence contentDescription,
             Preference.OnPreferenceClickListener listener) {
-        AccessiblePreference pref = new AccessiblePreference(mActivity, contentDescription);
+        DimmableIconPreference pref = new DimmableIconPreference(mActivity, contentDescription);
         pref.setIcon(icon);
         pref.setTitle(label);
         if (isHighBattery) {
@@ -198,7 +176,7 @@ public class RecentLocationApps {
         int uid = ops.getUid();
         int userId = UserHandle.getUserId(uid);
 
-        AccessiblePreference preference = null;
+        DimmableIconPreference preference = null;
         try {
             IPackageManager ipm = AppGlobals.getPackageManager();
             ApplicationInfo appInfo =
@@ -215,6 +193,11 @@ public class RecentLocationApps {
             Drawable icon = mPackageManager.getUserBadgedIcon(appIcon, userHandle);
             CharSequence appLabel = mPackageManager.getApplicationLabel(appInfo);
             CharSequence badgedAppLabel = mPackageManager.getUserBadgedLabel(appLabel, userHandle);
+            if (appLabel.toString().contentEquals(badgedAppLabel)) {
+                // If badged label is not different from original then no need for it as
+                // a separate content description.
+                badgedAppLabel = null;
+            }
             preference = createRecentLocationEntry(icon,
                     appLabel, highBattery, badgedAppLabel,
                     new PackageEntryClickedListener(packageName));
index edf67b8..f0a0ff3 100644 (file)
@@ -32,11 +32,15 @@ import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
+
 import com.android.settings.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -99,27 +103,29 @@ class SettingsInjector {
     }
 
     /**
-     * Returns a list with one {@link InjectedSetting} object for each {@link android.app.Service}
-     * that responds to {@link SettingInjectorService#ACTION_SERVICE_INTENT} and provides the
-     * expected setting metadata.
+     * Returns a list for a profile with one {@link InjectedSetting} object for each
+     * {@link android.app.Service} that responds to
+     * {@link SettingInjectorService#ACTION_SERVICE_INTENT} and provides the expected setting
+     * metadata.
      *
      * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
      *
      * TODO: unit test
      */
-    private List<InjectedSetting> getSettings() {
+    private List<InjectedSetting> getSettings(final UserHandle userHandle) {
         PackageManager pm = mContext.getPackageManager();
         Intent intent = new Intent(SettingInjectorService.ACTION_SERVICE_INTENT);
 
+        final int profileId = userHandle.getIdentifier();
         List<ResolveInfo> resolveInfos =
-                pm.queryIntentServices(intent, PackageManager.GET_META_DATA);
+                pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, profileId);
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Found services: " + resolveInfos);
+            Log.d(TAG, "Found services for profile id " + profileId + ": " + resolveInfos);
         }
         List<InjectedSetting> settings = new ArrayList<InjectedSetting>(resolveInfos.size());
         for (ResolveInfo resolveInfo : resolveInfos) {
             try {
-                InjectedSetting setting = parseServiceInfo(resolveInfo, pm);
+                InjectedSetting setting = parseServiceInfo(resolveInfo, userHandle, pm);
                 if (setting == null) {
                     Log.w(TAG, "Unable to load service info " + resolveInfo);
                 } else {
@@ -132,7 +138,7 @@ class SettingsInjector {
             }
         }
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "Loaded settings: " + settings);
+            Log.d(TAG, "Loaded settings for profile id " + profileId + ": " + settings);
         }
 
         return settings;
@@ -144,8 +150,8 @@ class SettingsInjector {
      *
      * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
      */
-    private static InjectedSetting parseServiceInfo(ResolveInfo service, PackageManager pm)
-            throws XmlPullParserException, IOException {
+    private static InjectedSetting parseServiceInfo(ResolveInfo service, UserHandle userHandle,
+            PackageManager pm) throws XmlPullParserException, IOException {
 
         ServiceInfo si = service.serviceInfo;
         ApplicationInfo ai = si.applicationInfo;
@@ -179,8 +185,9 @@ class SettingsInjector {
                         + SettingInjectorService.ATTRIBUTES_NAME + " tag");
             }
 
-            Resources res = pm.getResourcesForApplication(ai);
-            return parseAttributes(si.packageName, si.name, res, attrs);
+            Resources res = pm.getResourcesForApplicationAsUser(si.packageName,
+                    userHandle.getIdentifier());
+            return parseAttributes(si.packageName, si.name, userHandle, res, attrs);
         } catch (PackageManager.NameNotFoundException e) {
             throw new XmlPullParserException(
                     "Unable to load resources for package " + si.packageName);
@@ -194,8 +201,8 @@ class SettingsInjector {
     /**
      * Returns an immutable representation of the static attributes for the setting, or null.
      */
-    private static InjectedSetting parseAttributes(
-            String packageName, String className, Resources res, AttributeSet attrs) {
+    private static InjectedSetting parseAttributes(String packageName, String className,
+            UserHandle userHandle, Resources res, AttributeSet attrs) {
 
         TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.SettingInjectorService);
         try {
@@ -211,7 +218,7 @@ class SettingsInjector {
                         + ", settingsActivity: " + settingsActivity);
             }
             return InjectedSetting.newInstance(packageName, className,
-                    title, iconId, settingsActivity);
+                    title, iconId, userHandle, settingsActivity);
         } finally {
             sa.recycle();
         }
@@ -219,13 +226,24 @@ class SettingsInjector {
 
     /**
      * Gets a list of preferences that other apps have injected.
+     *
+     * @param profileId Identifier of the user/profile to obtain the injected settings for or
+     *                  UserHandle.USER_CURRENT for all profiles associated with current user.
      */
-    public List<Preference> getInjectedSettings() {
-        Iterable<InjectedSetting> settings = getSettings();
+    public List<Preference> getInjectedSettings(final int profileId) {
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        final List<UserHandle> profiles = um.getUserProfiles();
         ArrayList<Preference> prefs = new ArrayList<Preference>();
-        for (InjectedSetting setting : settings) {
-            Preference pref = addServiceSetting(prefs, setting);
-            mSettings.add(new Setting(setting, pref));
+        final int profileCount = profiles.size();
+        for (int i = 0; i < profileCount; ++i) {
+            final UserHandle userHandle = profiles.get(i);
+            if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
+                Iterable<InjectedSetting> settings = getSettings(userHandle);
+                for (InjectedSetting setting : settings) {
+                    Preference pref = addServiceSetting(prefs, setting);
+                    mSettings.add(new Setting(setting, pref));
+                }
+            }
         }
 
         reloadStatusMessages();
@@ -247,24 +265,46 @@ class SettingsInjector {
      * Adds an injected setting to the root.
      */
     private Preference addServiceSetting(List<Preference> prefs, InjectedSetting info) {
-        Preference pref = new DimmableIconPreference(mContext);
+        PackageManager pm = mContext.getPackageManager();
+        Drawable appIcon = pm.getDrawable(info.packageName, info.iconId, null);
+        Drawable icon = pm.getUserBadgedIcon(appIcon, info.mUserHandle);
+        CharSequence badgedAppLabel = pm.getUserBadgedLabel(info.title, info.mUserHandle);
+        if (info.title.contentEquals(badgedAppLabel)) {
+            // If badged label is not different from original then no need for it as
+            // a separate content description.
+            badgedAppLabel = null;
+        }
+        Preference pref = new DimmableIconPreference(mContext, badgedAppLabel);
         pref.setTitle(info.title);
         pref.setSummary(null);
-        PackageManager pm = mContext.getPackageManager();
-        Drawable icon = pm.getDrawable(info.packageName, info.iconId, null);
         pref.setIcon(icon);
-
-        // Activity to start if they click on the preference. Must start in new task to ensure
-        // that "android.settings.LOCATION_SOURCE_SETTINGS" brings user back to Settings > Location.
-        Intent settingIntent = new Intent();
-        settingIntent.setClassName(info.packageName, info.settingsActivity);
-        settingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        pref.setIntent(settingIntent);
+        pref.setOnPreferenceClickListener(new ServiceSettingClickedListener(info));
 
         prefs.add(pref);
         return pref;
     }
 
+    private class ServiceSettingClickedListener
+            implements Preference.OnPreferenceClickListener {
+        private InjectedSetting mInfo;
+
+        public ServiceSettingClickedListener(InjectedSetting info) {
+            mInfo = info;
+        }
+
+        @Override
+        public boolean onPreferenceClick(Preference preference) {
+            // Activity to start if they click on the preference. Must start in new task to ensure
+            // that "android.settings.LOCATION_SOURCE_SETTINGS" brings user back to
+            // Settings > Location.
+            Intent settingIntent = new Intent();
+            settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity);
+            settingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivityAsUser(settingIntent, mInfo.mUserHandle);
+            return true;
+        }
+    }
+
     /**
      * Loads the setting status values one at a time. Each load starts a subclass of {@link
      * SettingInjectorService}, so to reduce memory pressure we don't want to load too many at
@@ -451,9 +491,9 @@ class SettingsInjector {
                 startMillis = 0;
             }
 
-            // Start the service, making sure that this is attributed to the current user rather
-            // than the system user.
-            mContext.startServiceAsUser(intent, android.os.Process.myUserHandle());
+            // Start the service, making sure that this is attributed to the user associated with
+            // the setting rather than the system user.
+            mContext.startServiceAsUser(intent, setting.mUserHandle);
         }
 
         public long getElapsedTime() {