Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95fb3f6d authored by Jeremy Klein's avatar Jeremy Klein Committed by android-build-merger
Browse files

Set the tether Entitlement app as active when enabling tethering.

am: b04fae20

Change-Id: Ie74056677682e858625ea571049efc52154797b7
parents ff36f178 b04fae20
Loading
Loading
Loading
Loading
+63 −8
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.usage.UsageStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -29,6 +30,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.ResultReceiver;
@@ -63,6 +66,7 @@ public class TetherService extends Service {

    private int mCurrentTypeIndex;
    private boolean mInProvisionCheck;
    private UsageStatsManagerWrapper mUsageManagerWrapper;
    private ArrayList<Integer> mCurrentTethers;
    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_BLUETOOTH, new ArrayList<ResultReceiver>());
        if (mUsageManagerWrapper == null) {
            mUsageManagerWrapper = new UsageStatsManagerWrapper(this);
        }
    }

    @Override
@@ -228,17 +235,43 @@ public class TetherService extends Service {

    private void startProvisioning(int index) {
        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(
                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);
        int type = mCurrentTethers.get(index);
        intent.putExtra(TETHER_CHOICE, type);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);

            sendBroadcast(intent);
            mInProvisionCheck = true;
        return intent;
    }

    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);
        }
    }
}
+88 −0
Original line number Diff line number Diff line
@@ -35,11 +35,16 @@ import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
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.Editor;
import android.content.res.Resources;
@@ -61,10 +66,16 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

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> {

    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_NO_UI_ACTION = "testNoUiProvisioningRequestAction";
    private static final int BOGUS_RECEIVER_RESULT = -5;
@@ -75,6 +86,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {

    private TetherService mService;
    private MockResources mResources;
    private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper;
    int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT;
    private int mLastTetherRequestType = TETHERING_INVALID;
    private int mProvisionResponse = BOGUS_RECEIVER_RESULT;
@@ -83,6 +95,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {

    @Mock private AlarmManager mAlarmManager;
    @Mock private ConnectivityManager mConnectivityManager;
    @Mock private PackageManager mPackageManager;
    @Mock private WifiManager mWifiManager;
    @Mock private SharedPreferences mPrefs;
    @Mock private Editor mPrefEditor;
@@ -115,6 +128,27 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        when(mPrefs.edit()).thenReturn(mPrefEditor);
        when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn(
                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
@@ -139,6 +173,19 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        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() {
        Intent intent = new Intent();
        intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI);
@@ -229,6 +276,19 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        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) {
        long startTime = SystemClock.uptimeMillis();
        while (true) {
@@ -307,6 +367,11 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
            return super.getSharedPreferences(name, mode);
        }

        @Override
        public PackageManager getPackageManager() {
            return mPackageManager;
        }

        @Override
        public Object getSystemService(String name) {
            if (ALARM_SERVICE.equals(name)) {
@@ -355,4 +420,27 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
                    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);
        }
    }
}