Set the tether Entitlement app as active when enabling tethering. am: b04fae204e am: 95fb3f6d3c

am: fc0b9c2f7e

Change-Id: I7bab3f9bede7dc6e3454e4a45aecb6ce25025762
This commit is contained in:
Jeremy Klein
2016-08-03 19:20:13 +00:00
committed by android-build-merger
2 changed files with 151 additions and 8 deletions

View File

@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.app.usage.UsageStatsManager;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
@@ -29,6 +30,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.IBinder; import android.os.IBinder;
import android.os.ResultReceiver; import android.os.ResultReceiver;
@@ -63,6 +66,7 @@ public class TetherService extends Service {
private int mCurrentTypeIndex; private int mCurrentTypeIndex;
private boolean mInProvisionCheck; private boolean mInProvisionCheck;
private UsageStatsManagerWrapper mUsageManagerWrapper;
private ArrayList<Integer> mCurrentTethers; private ArrayList<Integer> mCurrentTethers;
private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks;
@@ -87,6 +91,9 @@ public class TetherService extends Service {
mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>()); mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>());
mPendingCallbacks.put( mPendingCallbacks.put(
ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>()); ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>());
if (mUsageManagerWrapper == null) {
mUsageManagerWrapper = new UsageStatsManagerWrapper(this);
}
} }
@Override @Override
@@ -228,17 +235,43 @@ public class TetherService extends Service {
private void startProvisioning(int index) { private void startProvisioning(int index) {
if (index < mCurrentTethers.size()) { if (index < mCurrentTethers.size()) {
Intent intent = getProvisionBroadcastIntent(index);
setEntitlementAppActive(index);
if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
+ " type: " + mCurrentTethers.get(index));
sendBroadcast(intent);
mInProvisionCheck = true;
}
}
private Intent getProvisionBroadcastIntent(int index) {
String provisionAction = getResources().getString( String provisionAction = getResources().getString(
com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui);
if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + provisionAction + " type: "
+ mCurrentTethers.get(index));
Intent intent = new Intent(provisionAction); Intent intent = new Intent(provisionAction);
int type = mCurrentTethers.get(index); int type = mCurrentTethers.get(index);
intent.putExtra(TETHER_CHOICE, type); intent.putExtra(TETHER_CHOICE, type);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
sendBroadcast(intent); return intent;
mInProvisionCheck = true; }
private void setEntitlementAppActive(int index) {
final PackageManager packageManager = getPackageManager();
Intent intent = getProvisionBroadcastIntent(index);
List<ResolveInfo> resolvers =
packageManager.queryBroadcastReceivers(intent, PackageManager.MATCH_ALL);
if (resolvers.isEmpty()) {
Log.e(TAG, "No found BroadcastReceivers for provision intent.");
return;
}
for (ResolveInfo resolver : resolvers) {
if (resolver.activityInfo.applicationInfo.isSystemApp()) {
String packageName = resolver.activityInfo.packageName;
mUsageManagerWrapper.setAppInactive(packageName, false);
}
} }
} }
@@ -335,4 +368,26 @@ public class TetherService extends Service {
} }
}; };
@VisibleForTesting
void setUsageStatsManagerWrapper(UsageStatsManagerWrapper wrapper) {
mUsageManagerWrapper = wrapper;
}
/**
* A static helper class used for tests. UsageStatsManager cannot be mocked out becasue
* it's marked final. This class can be mocked out instead.
*/
@VisibleForTesting
public static class UsageStatsManagerWrapper {
private final UsageStatsManager mUsageStatsManager;
UsageStatsManagerWrapper(Context context) {
mUsageStatsManager = (UsageStatsManager)
context.getSystemService(Context.USAGE_STATS_SERVICE);
}
void setAppInactive(String packageName, boolean isInactive) {
mUsageStatsManager.setAppInactive(packageName, isInactive);
}
}
} }

View File

@@ -35,11 +35,16 @@ import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import android.app.Activity; import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.content.res.Resources; import android.content.res.Resources;
@@ -61,10 +66,16 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TetherServiceTest extends ServiceTestCase<TetherService> { public class TetherServiceTest extends ServiceTestCase<TetherService> {
private static final String TAG = "TetherServiceTest"; private static final String TAG = "TetherServiceTest";
private static final String FAKE_PACKAGE_NAME = "com.some.package.name";
private static final String ENTITLEMENT_PACKAGE_NAME = "com.some.entitlement.name";
private static final String TEST_RESPONSE_ACTION = "testProvisioningResponseAction"; private static final String TEST_RESPONSE_ACTION = "testProvisioningResponseAction";
private static final String TEST_NO_UI_ACTION = "testNoUiProvisioningRequestAction"; private static final String TEST_NO_UI_ACTION = "testNoUiProvisioningRequestAction";
private static final int BOGUS_RECEIVER_RESULT = -5; private static final int BOGUS_RECEIVER_RESULT = -5;
@@ -75,6 +86,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
private TetherService mService; private TetherService mService;
private MockResources mResources; private MockResources mResources;
private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper;
int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT; int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
private int mLastTetherRequestType = TETHERING_INVALID; private int mLastTetherRequestType = TETHERING_INVALID;
private int mProvisionResponse = BOGUS_RECEIVER_RESULT; private int mProvisionResponse = BOGUS_RECEIVER_RESULT;
@@ -83,6 +95,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
@Mock private AlarmManager mAlarmManager; @Mock private AlarmManager mAlarmManager;
@Mock private ConnectivityManager mConnectivityManager; @Mock private ConnectivityManager mConnectivityManager;
@Mock private PackageManager mPackageManager;
@Mock private WifiManager mWifiManager; @Mock private WifiManager mWifiManager;
@Mock private SharedPreferences mPrefs; @Mock private SharedPreferences mPrefs;
@Mock private Editor mPrefEditor; @Mock private Editor mPrefEditor;
@@ -115,6 +128,27 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
when(mPrefs.edit()).thenReturn(mPrefEditor); when(mPrefs.edit()).thenReturn(mPrefEditor);
when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn( when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn(
mPrefEditor); mPrefEditor);
mUsageStatsManagerWrapper = new FakeUsageStatsManagerWrapper(mContext);
ResolveInfo systemAppResolveInfo = new ResolveInfo();
ActivityInfo systemActivityInfo = new ActivityInfo();
systemActivityInfo.packageName = ENTITLEMENT_PACKAGE_NAME;
ApplicationInfo systemAppInfo = new ApplicationInfo();
systemAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
systemActivityInfo.applicationInfo = systemAppInfo;
systemAppResolveInfo.activityInfo = systemActivityInfo;
ResolveInfo nonSystemResolveInfo = new ResolveInfo();
ActivityInfo nonSystemActivityInfo = new ActivityInfo();
nonSystemActivityInfo.packageName = FAKE_PACKAGE_NAME;
nonSystemActivityInfo.applicationInfo = new ApplicationInfo();
nonSystemResolveInfo.activityInfo = nonSystemActivityInfo;
List<ResolveInfo> resolvers = new ArrayList();
resolvers.add(nonSystemResolveInfo);
resolvers.add(systemAppResolveInfo);
when(mPackageManager.queryBroadcastReceivers(
any(Intent.class), eq(PackageManager.MATCH_ALL))).thenReturn(resolvers);
} }
@Override @Override
@@ -139,6 +173,19 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR)); assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
} }
public void testStartKeepsProvisionAppActive() {
setupService();
getService().setUsageStatsManagerWrapper(mUsageStatsManagerWrapper);
runProvisioningForType(TETHERING_WIFI);
assertTrue(waitForProvisionRequest(TETHERING_WIFI));
assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));
assertFalse(mUsageStatsManagerWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME));
// Non-system handler of the intent action should stay idle.
assertTrue(mUsageStatsManagerWrapper.isAppInactive(FAKE_PACKAGE_NAME));
}
public void testScheduleRechecks() { public void testScheduleRechecks() {
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI);
@@ -229,6 +276,19 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
startService(intent); startService(intent);
} }
private boolean waitForAppInactive(UsageStatsManager usageStatsManager, String packageName) {
long startTime = SystemClock.uptimeMillis();
while (true) {
if (usageStatsManager.isAppInactive(packageName)) {
return true;
}
if ((SystemClock.uptimeMillis() - startTime) > PROVISION_TIMEOUT) {
return false;
}
SystemClock.sleep(SHORT_TIMEOUT);
}
}
private boolean waitForProvisionRequest(int expectedType) { private boolean waitForProvisionRequest(int expectedType) {
long startTime = SystemClock.uptimeMillis(); long startTime = SystemClock.uptimeMillis();
while (true) { while (true) {
@@ -307,6 +367,11 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
return super.getSharedPreferences(name, mode); return super.getSharedPreferences(name, mode);
} }
@Override
public PackageManager getPackageManager() {
return mPackageManager;
}
@Override @Override
public Object getSystemService(String name) { public Object getSystemService(String name) {
if (ALARM_SERVICE.equals(name)) { if (ALARM_SERVICE.equals(name)) {
@@ -355,4 +420,27 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
responseIntent, android.Manifest.permission.CONNECTIVITY_INTERNAL); responseIntent, android.Manifest.permission.CONNECTIVITY_INTERNAL);
} }
} }
private static class FakeUsageStatsManagerWrapper
extends TetherService.UsageStatsManagerWrapper {
private final Set<String> mActivePackages;
FakeUsageStatsManagerWrapper(Context context) {
super(context);
mActivePackages = new HashSet<>();
}
@Override
void setAppInactive(String packageName, boolean isInactive) {
if (!isInactive) {
mActivePackages.add(packageName);
} else {
mActivePackages.remove(packageName);
}
}
boolean isAppInactive(String packageName) {
return !mActivePackages.contains(packageName);
}
}
} }