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

Commit 3548a5eb authored by Mark Chien's avatar Mark Chien Committed by Automerger Merge Worker
Browse files

Merge "Remove schedule recheck logic from TetherService" am: 9f1fe57b

Original change: https://android-review.googlesource.com/c/platform/packages/apps/Settings/+/1298536

Change-Id: If30d8e11f18380b3ab5f2ef840951d550532077a
parents d6d12e55 9f1fe57b
Loading
Loading
Loading
Loading
+0 −55
Original line number Diff line number Diff line

package com.android.settings.wifi.tether;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.util.Log;

/**
 * This receiver catches when quick settings turns off the hotspot, so we can
 * cancel the alarm in that case.  All other cancels are handled in tethersettings.
 */
public class HotspotOffReceiver extends BroadcastReceiver {

    private static final String TAG = "HotspotOffReceiver";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private Context mContext;
    private boolean mRegistered;

    public HotspotOffReceiver(Context context) {
        mContext = context;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED) {
                if (DEBUG) Log.d(TAG, "TetherService.cancelRecheckAlarmIfNecessary called");
                // The hotspot has been turned off, we don't need to recheck tethering.
                TetherService.cancelRecheckAlarmIfNecessary(
                        context, ConnectivityManager.TETHERING_WIFI);
            }
        }
    }

    public void register() {
        if (!mRegistered) {
            mContext.registerReceiver(this,
                new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
            mRegistered = true;
        }
    }

    public void unregister() {
        if (mRegistered) {
            mContext.unregisterReceiver(this);
            mRegistered = false;
        }
    }
}
+2 −68
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@
package com.android.settings.wifi.tether;

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;
@@ -36,7 +34,6 @@ import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -74,7 +71,6 @@ public class TetherService extends Service {
    private TetherServiceWrapper mWrapper;
    private ArrayList<Integer> mCurrentTethers;
    private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks;
    private HotspotOffReceiver mHotspotReceiver;

    @Override
    public IBinder onBind(Intent intent) {
@@ -97,7 +93,6 @@ public class TetherService extends Service {
        mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>());
        mPendingCallbacks.put(
                ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>());
        mHotspotReceiver = new HotspotOffReceiver(this);
    }

    @Override
@@ -146,20 +141,11 @@ public class TetherService extends Service {
                if (index >= 0) {
                    removeTypeAtIndex(index);
                }
                cancelAlarmIfNecessary();
            } else {
                if (DEBUG) Log.d(TAG, "Don't cancel alarm during provisioning");
                if (DEBUG) Log.d(TAG, "Don't remove tether type during provisioning");
            }
        }

        // Only set the alarm if we have one tether, meaning the one just added,
        // to avoid setting it when it was already set previously for another
        // type.
        if (intent.getBooleanExtra(ConnectivityManager.EXTRA_SET_ALARM, false)
                && mCurrentTethers.size() == 1) {
            scheduleAlarm();
        }

        if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) {
            startProvisioning(mCurrentTypeIndex);
        } else if (!mInProvisionCheck) {
@@ -182,16 +168,11 @@ public class TetherService extends Service {
        SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
        prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit();

        unregisterReceivers();
        unregisterReceiver(mReceiver);
        if (DEBUG) Log.d(TAG, "Destroying TetherService");
        super.onDestroy();
    }

    private void unregisterReceivers() {
        unregisterReceiver(mReceiver);
        mHotspotReceiver.unregister();
    }

    private void removeTypeAtIndex(int index) {
        mCurrentTethers.remove(index);
        // If we are currently in the middle of a check, we may need to adjust the
@@ -202,11 +183,6 @@ public class TetherService extends Service {
        }
    }

    @VisibleForTesting
    void setHotspotOffReceiver(HotspotOffReceiver receiver) {
        mHotspotReceiver = receiver;
    }

    private ArrayList<Integer> stringToTethers(String tethersStr) {
        ArrayList<Integer> ret = new ArrayList<Integer>();
        if (TextUtils.isEmpty(tethersStr)) return ret;
@@ -304,48 +280,6 @@ public class TetherService extends Service {
        }
    }

    @VisibleForTesting
    void scheduleAlarm() {
        Intent intent = new Intent(this, TetherService.class);
        intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);

        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int period = getResourceForActiveDataSubId().getInteger(
                com.android.internal.R.integer.config_mobile_hotspot_provision_check_period);
        long periodMs = period * MS_PER_HOUR;
        long firstTime = SystemClock.elapsedRealtime() + periodMs;
        if (DEBUG) Log.d(TAG, "Scheduling alarm at interval " + periodMs);
        alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, periodMs,
                pendingIntent);
        mHotspotReceiver.register();
    }

    /**
     * Cancels the recheck alarm only if no tethering is currently active.
     *
     * Runs in the background, to get access to bluetooth service that takes time to bind.
     */
    public static void cancelRecheckAlarmIfNecessary(final Context context, int type) {
        Intent intent = new Intent(context, TetherService.class);
        intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
        context.startService(intent);
    }

    @VisibleForTesting
    void cancelAlarmIfNecessary() {
        if (mCurrentTethers.size() != 0) {
            if (DEBUG) Log.d(TAG, "Tethering still active, not cancelling alarm");
            return;
        }
        Intent intent = new Intent(this, TetherService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
        if (DEBUG) Log.d(TAG, "Tethering no longer active, canceling recheck");
        mHotspotReceiver.unregister();
    }

    private void fireCallbacksForType(int type, int result) {
        List<ResultReceiver> callbacksForType = mPendingCallbacks.get(type);
        if (callbacksForType == null) {
+0 −118
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.settings.wifi.tether;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.SharedPreferences;
import android.net.wifi.WifiManager;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowApplication.Wrapper;
import org.robolectric.util.ReflectionHelpers;

import java.util.ArrayList;

@RunWith(RobolectricTestRunner.class)
public class TetherServiceTest {

    @Mock
    private Context mContext;

    private Context mAppContext;
    private TetherService mService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mAppContext = RuntimeEnvironment.application;
        mService = new TetherService();
        ReflectionHelpers.setField(mService, "mBase", mAppContext);
        mService.setHotspotOffReceiver(new HotspotOffReceiver(mContext));
    }

    @Test
    public void scheduleAlarm_shouldRegisterReceiver() {
        mService.setHotspotOffReceiver(new HotspotOffReceiver(mAppContext));

        mService.scheduleAlarm();

        boolean found = false;
        for (Wrapper wrapper : ShadowApplication.getInstance().getRegisteredReceivers()) {
            if (wrapper.intentFilter.matchAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                found = true;
                break;
            }
        }

        assertThat(found).isTrue();
    }

    @Test
    public void cancelAlarmIfNecessary_hasActiveTethers_shouldNotUnregisterReceiver() {
        mService.scheduleAlarm();
        final ArrayList<Integer> tethers = new ArrayList<>();
        tethers.add(1);
        ReflectionHelpers.setField(mService, "mCurrentTethers", tethers);

        mService.cancelAlarmIfNecessary();
        verify(mContext, never()).unregisterReceiver(any(HotspotOffReceiver.class));
    }

    @Test
    public void cancelAlarmIfNecessary_noActiveTethers_shouldUnregisterReceiver() {
        final ArrayList<Integer> tethers = new ArrayList<>();
        ReflectionHelpers.setField(mService, "mCurrentTethers", tethers);
        mService.scheduleAlarm();

        mService.cancelAlarmIfNecessary();
        verify(mContext).unregisterReceiver(any(HotspotOffReceiver.class));
    }

    @Test
    public void onDestroy_shouldUnregisterReceiver() {
        final ArrayList<Integer> tethers = new ArrayList<>();
        ReflectionHelpers.setField(mService, "mCurrentTethers", tethers);
        ReflectionHelpers.setField(mService, "mBase", mContext);
        final SharedPreferences prefs = mock(SharedPreferences .class);
        final SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
        when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(prefs);
        when(prefs.edit()).thenReturn(editor);
        when(editor.putString(anyString(), anyString())).thenReturn(editor);
        final HotspotOffReceiver hotspotOffReceiver = mock(HotspotOffReceiver.class);
        mService.setHotspotOffReceiver(hotspotOffReceiver);

        mService.onDestroy();

        verify(hotspotOffReceiver).unregister();
    }
}
+1 −45
Original line number Diff line number Diff line
@@ -18,9 +18,7 @@ package com.android.settings.wifi.tether;

import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_INVALID;
import static android.net.ConnectivityManager.TETHERING_USB;
@@ -30,13 +28,11 @@ import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
@@ -92,7 +88,6 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
    private ProvisionReceiver mProvisionReceiver;
    private Receiver mResultReceiver;

    @Mock private AlarmManager mAlarmManager;
    @Mock private ConnectivityManager mConnectivityManager;
    @Mock private PackageManager mPackageManager;
    @Mock private WifiManager mWifiManager;
@@ -158,15 +153,6 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        super.tearDown();
    }

    private void cancelAllProvisioning() {
        int[] types = new int[]{TETHERING_BLUETOOTH, TETHERING_WIFI, TETHERING_USB};
        for (int type : types) {
            Intent intent = new Intent();
            intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
            startService(intent);
        }
    }

    public void testStartForProvision() {
        runProvisioningForType(TETHERING_WIFI);

@@ -184,19 +170,6 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        assertTrue(mWrapper.isAppInactive(FAKE_PACKAGE_NAME));
    }

    public void testScheduleRechecks() {
        Intent intent = new Intent();
        intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI);
        intent.putExtra(EXTRA_SET_ALARM, true);
        startService(intent);

        long period = TEST_CHECK_PERIOD * MS_PER_HOUR;
        verify(mAlarmManager).setRepeating(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
                eq(period), mPiCaptor.capture());
        PendingIntent pi = mPiCaptor.getValue();
        assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName());
    }

    public void testStartMultiple() {
        runProvisioningForType(TETHERING_WIFI);

@@ -251,21 +224,6 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {
        verify(mConnectivityManager).setUsbTethering(eq(false));
    }

    public void testCancelAlarm() {
        runProvisioningForType(TETHERING_WIFI);

        assertTrue(waitForProvisionRequest(TETHERING_WIFI));
        assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR));

        Intent intent = new Intent();
        intent.putExtra(EXTRA_REM_TETHER_TYPE, TETHERING_WIFI);
        startService(intent);

        verify(mAlarmManager).cancel(mPiCaptor.capture());
        PendingIntent pi = mPiCaptor.getValue();
        assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName());
    }

    public void testIgnoreOutdatedRequest() {
        Intent intent = new Intent();
        intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI);
@@ -387,9 +345,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> {

        @Override
        public Object getSystemService(String name) {
            if (ALARM_SERVICE.equals(name)) {
                return mAlarmManager;
            } else if (CONNECTIVITY_SERVICE.equals(name)) {
            if (CONNECTIVITY_SERVICE.equals(name)) {
                return mConnectivityManager;
            } else if (WIFI_SERVICE.equals(name)) {
                return mWifiManager;