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

Commit 84101bef authored by Jeremy Klein's avatar Jeremy Klein Committed by Android (Google) Code Review
Browse files

Merge "Set the tether Entitlement app as active when enabling tethering." into nyc-mr1-dev

parents cd498470 b04fae20
Loading
Loading
Loading
Loading
+63 −8
Original line number Original line Diff line number Diff line
@@ -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);
        }
    }
}
}
+88 −0
Original line number Original line 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.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);
        }
    }
}
}