• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.permissioncontroller.permission.utils;
17 
18 import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;
19 
20 import android.Manifest;
21 import android.app.AlertDialog;
22 import android.content.ActivityNotFoundException;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.DialogInterface.OnClickListener;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.location.LocationManager;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.os.UserHandle;
33 import android.provider.Settings;
34 import android.util.Log;
35 
36 import androidx.annotation.NonNull;
37 
38 import com.android.permissioncontroller.PermissionControllerApplication;
39 import com.android.permissioncontroller.R;
40 
41 import java.util.ArrayList;
42 
43 public class LocationUtils {
44 
45     public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION;
46     public static final String ACTIVITY_RECOGNITION_PERMISSION =
47             Manifest.permission_group.ACTIVITY_RECOGNITION;
48 
49     private static final String TAG = LocationUtils.class.getSimpleName();
50     private static final long LOCATION_UPDATE_DELAY_MS = 1000;
51     private static final Handler sMainHandler = new Handler(Looper.getMainLooper());
52 
showLocationDialog(final Context context, CharSequence label)53     public static void showLocationDialog(final Context context, CharSequence label) {
54         new AlertDialog.Builder(context)
55                 .setIcon(R.drawable.ic_dialog_alert_material)
56                 .setTitle(android.R.string.dialog_alert_title)
57                 .setMessage(context.getString(R.string.location_warning, label))
58                 .setNegativeButton(R.string.ok, null)
59                 .setPositiveButton(R.string.location_settings, new OnClickListener() {
60                     @Override
61                     public void onClick(DialogInterface dialog, int which) {
62                         context.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
63                     }
64                 })
65                 .show();
66     }
67 
68     /** Start the settings page for the location controller extra package. */
startLocationControllerExtraPackageSettings(@onNull Context context, @NonNull UserHandle user)69     public static void startLocationControllerExtraPackageSettings(@NonNull Context context,
70             @NonNull UserHandle user) {
71         try {
72             context.startActivityAsUser(new Intent(
73                         Settings.ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS), user);
74         } catch (ActivityNotFoundException e) {
75             // In rare cases where location controller extra package is set, but
76             // no activity exists to handle the location controller extra package settings
77             // intent, log an error instead of crashing permission controller.
78             Log.e(TAG, "No activity to handle "
79                         + "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS");
80         }
81     }
82 
isLocationEnabled(Context context)83     public static boolean isLocationEnabled(Context context) {
84         return context.getSystemService(LocationManager.class).isLocationEnabled();
85     }
86 
87     /** Checks if the provided package is a location provider. */
isLocationProvider(Context context, String packageName)88     public static boolean isLocationProvider(Context context, String packageName) {
89         return context.getSystemService(LocationManager.class).isProviderPackage(packageName);
90     }
91 
isLocationGroupAndProvider(Context context, String groupName, String packageName)92     public static boolean isLocationGroupAndProvider(Context context, String groupName,
93             String packageName) {
94         return LOCATION_PERMISSION.equals(groupName) && isLocationProvider(context, packageName);
95     }
96 
isLocationGroupAndControllerExtraPackage(@onNull Context context, @NonNull String groupName, @NonNull String packageName)97     public static boolean isLocationGroupAndControllerExtraPackage(@NonNull Context context,
98             @NonNull String groupName, @NonNull String packageName) {
99         return (LOCATION_PERMISSION.equals(groupName)
100             || ACTIVITY_RECOGNITION_PERMISSION.equals(groupName))
101                 && packageName.equals(context.getSystemService(LocationManager.class)
102                         .getExtraLocationControllerPackage());
103     }
104 
105     /** Returns whether the location controller extra package is enabled. */
isExtraLocationControllerPackageEnabled(Context context)106     public static boolean isExtraLocationControllerPackageEnabled(Context context) {
107         try {
108             return context.getSystemService(LocationManager.class)
109                     .isExtraLocationControllerPackageEnabled();
110         } catch (Exception e) {
111             return false;
112         }
113 
114     }
115 
116     /**
117      * A Listener which responds to enabling or disabling of location on the device
118      */
119     public interface LocationListener {
120 
121         /**
122          * A callback run any time we receive a broadcast stating the location enable state has
123          * changed.
124          * @param enabled Whether or not location is enabled
125          */
onLocationStateChange(boolean enabled)126         void onLocationStateChange(boolean enabled);
127     }
128 
129     private static final ArrayList<LocationListener> sLocationListeners = new ArrayList<>();
130 
131     private static BroadcastReceiver sLocationBroadcastReceiver = new BroadcastReceiver() {
132         @Override
133         public void onReceive(Context context, Intent intent) {
134             boolean isEnabled = intent.getBooleanExtra(EXTRA_LOCATION_ENABLED, true);
135             sMainHandler.postDelayed(() -> {
136                 synchronized (sLocationListeners) {
137                     for (LocationListener l : sLocationListeners) {
138                         l.onLocationStateChange(isEnabled);
139                     }
140                 }
141             }, LOCATION_UPDATE_DELAY_MS);
142         }
143     };
144 
145     /**
146      * Add a LocationListener, which will be notified if the location provider is enabled or
147      * disabled
148      * @param listener the listener to add
149      */
addLocationListener(LocationListener listener)150     public static void addLocationListener(LocationListener listener) {
151         synchronized (sLocationListeners) {
152             boolean wasEmpty = sLocationListeners.isEmpty();
153             sLocationListeners.add(listener);
154             if (wasEmpty) {
155                 IntentFilter intentFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
156                 PermissionControllerApplication.get().getApplicationContext()
157                         .registerReceiverForAllUsers(sLocationBroadcastReceiver, intentFilter,
158                                 null, null);
159             }
160         }
161     }
162 
163     /**
164      * Remove a LocationListener
165      * @param listener The listener to remove
166      *
167      * @return True if it was successfully removed, false otherwise
168      */
removeLocationListener(LocationListener listener)169     public static boolean removeLocationListener(LocationListener listener) {
170         synchronized (sLocationListeners) {
171             boolean success = sLocationListeners.remove(listener);
172             if (success && sLocationListeners.isEmpty()) {
173                 PermissionControllerApplication.get().getApplicationContext()
174                         .unregisterReceiver(sLocationBroadcastReceiver);
175             }
176             return success;
177         }
178     }
179 }
180