Android 定位功能使用状态监听
前言
由于做认证需要,提出增加对定位状态使用监听; 使用时显示定位icon,未使用时隐藏定位icon
使用
功能参考Android10 源码,如果需要查看源码可以在结尾查看
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
public class LocationListenerHelper extends BroadcastReceiver implements LocationController {
private static final String TAG = "LocationListenerHelper";
private static volatile LocationListenerHelper INSTANCE;
private static final int[] mHighPowerRequestAppOpArray
= new int[]{AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
private Context context;
private HandlerThread mHandlerThread = new HandlerThread("ActiveLocationHandlerThread");
private AppOpsManager mAppOpsManager;
private boolean mAreActiveLocationRequests;
private final ArrayList<LocationChangeCallback> mSettingsChangeCallbacks =
new ArrayList<LocationChangeCallback>();
private final H mHandler = new H();
public static LocationListenerHelper getInstance(Context context) {
if (INSTANCE == null) {
synchronized (LocationListenerHelper.class) {
if (INSTANCE == null) {
INSTANCE = new LocationListenerHelper(context);
}
}
}
return INSTANCE;
}
private LocationListenerHelper(Context context) {
this.context = context.getApplicationContext();
mHandlerThread.start();
IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, new Handler(mHandlerThread.getLooper()));
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
updateActiveLocationRequests();
}
/**
* Add a callback to listen for changes in location settings.
*/
public void addCallback(LocationChangeCallback cb) {
mSettingsChangeCallbacks.add(cb);
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
public void removeCallback(LocationChangeCallback cb) {
mSettingsChangeCallbacks.remove(cb);
}
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
updateActiveLocationRequests();
}
}
// Reads the active location requests and updates the status view if necessary.
private void updateActiveLocationRequests() {
boolean hadActiveLocationRequests = mAreActiveLocationRequests;
mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
}
/**
* Returns true if there currently exist active high power location requests.
*/
@VisibleForTesting
protected 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);
String packageName = packageOp.getPackageName();
Log.d(TAG, "areActiveHighPowerLocationRequests: packageName1 = " + packageName);
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;
}
@Override
public boolean isLocationActive() {
return mAreActiveLocationRequests;
}
private final class H extends Handler {
private static final int MSG_LOCATION_ACTIVE_CHANGED = 1;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOCATION_ACTIVE_CHANGED:
locationActiveChanged();
break;
}
}
private void locationActiveChanged() {
for (LocationChangeCallback callback : mSettingsChangeCallbacks) {
callback.onLocationActiveChanged(isLocationActive());
}
}
}
}
public interface LocationController {
boolean isLocationActive();
/**
* A callback for change in location settings (the user has enabled/disabled location).
*/
public interface LocationChangeCallback {
/**
* Called whenever location's state changes.
*
* @param active
*/
default void onLocationActiveChanged(boolean active) {
}
}
}
结尾
参考文献: LocationControllerImpl