1 /* 2 * Copyright (C) 2021 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 17 package com.android.cts.verifier.managedprovisioning; 18 19 import android.Manifest; 20 import android.app.Activity; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.location.Location; 24 import android.location.LocationManager; 25 import android.location.LocationRequest; 26 import android.os.Bundle; 27 import android.os.CancellationSignal; 28 import android.util.Log; 29 import android.widget.TextView; 30 31 import androidx.annotation.NonNull; 32 import androidx.core.app.ActivityCompat; 33 import androidx.core.content.ContextCompat; 34 35 import com.android.cts.verifier.R; 36 37 import java.util.List; 38 import java.util.stream.Collectors; 39 40 /** 41 * Activity that checks whether it can obtain location. Asks for permission in case it is missing. 42 * Result is reported to whoever invoked it with startActivityForResult. 43 */ 44 public class LocationCheckerActivity extends Activity { 45 private static final String TAG = LocationCheckerActivity.class.getSimpleName(); 46 47 public static final String ACTION_CHECK_LOCATION_PRIMARY = 48 "com.android.cts.verifier.managedprovisioning.CHECK_LOCATION_ACCESS_PRIMARY"; 49 public static final String ACTION_CHECK_LOCATION_WORK = 50 "com.android.cts.verifier.managedprovisioning.CHECK_LOCATION_ACCESS_WORK"; 51 public static final String WORK_ACTIVITY_ALIAS = 52 "com.android.cts.verifier.managedprovisioning.WorkLocationCheckerActivityAlias"; 53 54 public static final String EXTRA_ERROR_ID = "extra-error-id"; 55 public static final int LOCATION_PERMISSION_REQUEST = 125; 56 private static final int REQUEST_MAX_DURATION_MILLIS = 15000; 57 58 private List<String> mProviders; 59 private LocationManager mLocationManager; 60 private TextView mStatusText; 61 private final CancellationSignal mCancellationSignal = new CancellationSignal(); 62 63 @Override onCreate(Bundle savedInstanceState)64 protected void onCreate(Bundle savedInstanceState) { 65 super.onCreate(savedInstanceState); 66 setContentView(R.layout.location_checker); 67 68 mLocationManager = getSystemService(LocationManager.class); 69 mStatusText = findViewById(R.id.status_text); 70 71 if (hasLocationPermission()) { 72 requestCurrentLocation(); 73 } else { 74 requestLocationPermission(); 75 } 76 } 77 requestCurrentLocation()78 private void requestCurrentLocation() { 79 synchronized (this) { 80 mProviders = mLocationManager.getAllProviders().stream() 81 .filter(mLocationManager::isProviderEnabled) 82 .collect(Collectors.toList()); 83 if (mProviders.isEmpty()) { 84 finish(R.string.provisioning_byod_location_no_provider); 85 return; 86 } 87 // Callback will be invoked with null if duration exceeded. 88 LocationRequest request = new LocationRequest.Builder(0) 89 .setDurationMillis(REQUEST_MAX_DURATION_MILLIS).build(); 90 // Request location from all available providers. 91 for (String provider: mProviders) { 92 mLocationManager.getCurrentLocation(provider, request, mCancellationSignal, 93 getMainExecutor(), l -> onLocation(provider, l)); 94 } 95 updateStatusLocked(); 96 } 97 } 98 updateStatusLocked()99 private void updateStatusLocked() { 100 String providers = String.join(", ", mProviders); 101 mStatusText.setText(getString(R.string.provisioning_byod_location_trying, providers)); 102 } 103 hasLocationPermission()104 private boolean hasLocationPermission() { 105 return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 106 == PackageManager.PERMISSION_GRANTED; 107 } 108 requestLocationPermission()109 private void requestLocationPermission() { 110 ActivityCompat.requestPermissions(this, 111 new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 112 LOCATION_PERMISSION_REQUEST); 113 } 114 115 @Override onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grants)116 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 117 @NonNull int[] grants) { 118 // Test that the right permission was granted. 119 if (requestCode == LOCATION_PERMISSION_REQUEST) { 120 if (!permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION) 121 || grants[0] != PackageManager.PERMISSION_GRANTED 122 || !hasLocationPermission()) { 123 Log.e(TAG, "The test needs location permission."); 124 finish(R.string.provisioning_byod_location_mode_enable_missing_permission); 125 return; 126 } 127 requestCurrentLocation(); 128 } 129 } 130 onLocation(String provider, Location location)131 private void onLocation(String provider, Location location) { 132 if (mCancellationSignal.isCanceled()) { 133 return; 134 } else if (location != null) { 135 mCancellationSignal.cancel(); 136 finish(-1 /* no error */); 137 } 138 139 // location == null, provider wasn't able to get location, see if there are more providers 140 synchronized (this) { 141 mProviders.remove(provider); 142 if (mProviders.isEmpty()) { 143 finish(R.string.provisioning_byod_location_failed); 144 } else { 145 updateStatusLocked(); 146 } 147 } 148 } 149 finish(int messageId)150 void finish(int messageId) { 151 Intent result = new Intent(); 152 result.putExtra(EXTRA_ERROR_ID, messageId); 153 setResult(Activity.RESULT_OK, result); 154 finish(); 155 } 156 } 157