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

Commit 99eeb003 authored by Joshua Duong's avatar Joshua Duong Committed by Android (Google) Code Review
Browse files

Merge "[adbwifi] Add qstile for wireless debugging." into rvc-dev

parents 32f28397 0f3eba36
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -3107,6 +3107,19 @@
                       android:value="true"/>
        </service>

        <service
            android:name=".development.qstile.DevelopmentTiles$WirelessDebugging"
            android:label="@string/enable_adb_wireless"
            android:icon="@drawable/tile_icon_debugging_wireless"
            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
            android:enabled="false">
            <intent-filter>
                <action android:name="android.service.quicksettings.action.QS_TILE" />
            </intent-filter>
            <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
                       android:value="true"/>
        </service>

        <activity
            android:name=".HelpTrampoline"
            android:exported="true"
+28 −0
Original line number Diff line number Diff line
<!--
    Copyright (C) 2020 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?android:attr/colorControlNormal">
  <path
      android:fillColor="#FFFFFFFF"
      android:pathData="M19,10.3L19,16A7,7 0,0 1,5 16L5,10.3ZM7.5,14.5l0.8,0.8a5.3,5.3 0,0 1,7.4 0l0.8,-0.8A6.3,6.3 0,0 0,7.5 14.5ZM10.8,17.8L12,19l1.2,-1.2A1.6,1.6 0,0 0,10.8 17.8ZM9.1,16.1l0.9,0.9a2.7,2.7 0,0 1,4 0l0.9,-0.9A4.3,4.3 0,0 0,9.1 16.1Z"/>
  <path
      android:fillColor="#FFFFFFFF"
      android:pathData="M15.6,3.9l1.1,-2c0.1,-0.2 0.1,-0.4 -0.1,-0.5a0.5,0.5 0,0 0,-0.6 0.1L14.8,3.6a6.8,6.8 0,0 0,-5.6 0L8,1.5a0.5,0.5 0,0 0,-0.6 -0.1c-0.2,0.1 -0.2,0.3 -0.1,0.5l1.1,2A7.1,7.1 0,0 0,5 9.3L19,9.3A7.1,7.1 0,0 0,15.6 3.9ZM8.8,7.6A0.9,0.9 0,0 1,8 6.8,0.9 0.9,0 0,1 8.8,6a0.8,0.8 0,1 1,0 1.6ZM15.2,7.6a0.8,0.8 0,1 1,0 -1.6,0.9 0.9,0 0,1 0.8,0.8A0.9,0.9 0,0 1,15.2 7.6Z"/>
</vector>
+4 −1
Original line number Diff line number Diff line
@@ -135,7 +135,10 @@ public class WirelessDebuggingPreferenceController extends DeveloperOptionsPrefe
        ((MasterSwitchPreference) preference).setChecked(enabled);
    }

    static boolean isWifiConnected(Context context) {
    /**
     * Returns true if connected to Wi-Fi network.
     */
    public static boolean isWifiConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        if (cm != null) {
+84 −1
Original line number Diff line number Diff line
@@ -16,13 +16,21 @@

package com.android.settings.development.qstile;

import static com.android.settings.development.AdbPreferenceController.ADB_SETTING_OFF;
import static com.android.settings.development.AdbPreferenceController.ADB_SETTING_ON;

import android.app.KeyguardManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.app.KeyguardManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -41,6 +49,8 @@ import androidx.annotation.VisibleForTesting;

import com.android.internal.app.LocalePicker;
import com.android.internal.statusbar.IStatusBarService;
import com.android.settings.R;
import com.android.settings.development.WirelessDebuggingPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
@@ -349,4 +359,77 @@ public abstract class DevelopmentTiles extends TileService {
            mSensorPrivacyManager.setSensorPrivacy(isEnabled);
        }
    }

    /**
     * Tile to control the "Wireless debugging" developer setting
     */
    public static class WirelessDebugging extends DevelopmentTiles {
        private Context mContext;
        private KeyguardManager mKeyguardManager;
        private Toast mToast;
        private final Handler mHandler = new Handler(Looper.getMainLooper());
        private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                refresh();
            }
        };

        @Override
        public void onCreate() {
            super.onCreate();
            mContext = getApplicationContext();
            mKeyguardManager = (KeyguardManager) mContext.getSystemService(
                    Context.KEYGUARD_SERVICE);
            mToast = Toast.makeText(mContext, R.string.adb_wireless_no_network_msg,
                    Toast.LENGTH_LONG);
        }

        @Override
        public void onStartListening() {
            super.onStartListening();
            getContentResolver().registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED), false,
                    mSettingsObserver);
        }

        @Override
        public void onStopListening() {
            super.onStopListening();
            getContentResolver().unregisterContentObserver(mSettingsObserver);
        }

        @Override
        protected boolean isEnabled() {
            return isAdbWifiEnabled();
        }

        @Override
        public void setIsEnabled(boolean isEnabled) {
            // Don't allow Wireless Debugging to be enabled from the lock screen.
            if (isEnabled && mKeyguardManager.isKeyguardLocked()) {
                return;
            }

            // Show error toast if not connected to Wi-Fi
            if (isEnabled && !WirelessDebuggingPreferenceController.isWifiConnected(mContext)) {
                // Close quick shade
                sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
                mToast.show();
                return;
            }

            writeAdbWifiSetting(isEnabled);
        }

        private boolean isAdbWifiEnabled() {
            return Settings.Global.getInt(getContentResolver(), Settings.Global.ADB_WIFI_ENABLED,
                    ADB_SETTING_OFF) != ADB_SETTING_OFF;
        }

        protected void writeAdbWifiSetting(boolean enabled) {
            Settings.Global.putInt(getContentResolver(), Settings.Global.ADB_WIFI_ENABLED,
                    enabled ? ADB_SETTING_ON : ADB_SETTING_OFF);
        }
    }
}
+220 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.development.qstile;

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

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings.Global;
import android.widget.Toast;

import com.android.settings.testutils.shadow.ShadowWirelessDebuggingPreferenceController;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowWirelessDebuggingPreferenceController.class})
public class WirelessDebuggingTest {
    @Mock
    private Toast mToast;
    @Mock
    private KeyguardManager mKeyguardManager;

    private Context mContext;
    private DevelopmentTiles.WirelessDebugging mWirelessDebugging;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mContext = RuntimeEnvironment.application;
        mWirelessDebugging = spy(new DevelopmentTiles.WirelessDebugging());
        doReturn(mContext.getContentResolver()).when(mWirelessDebugging).getContentResolver();
        ReflectionHelpers.setField(mWirelessDebugging, "mKeyguardManager", mKeyguardManager);
        ReflectionHelpers.setField(mWirelessDebugging, "mToast", mToast);
    }

    @After
    public void tearDown() {
        ShadowWirelessDebuggingPreferenceController.reset();
    }

    @Test
    public void adbWifiEnabled_shouldReturnEnabled() {
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);

        assertThat(mWirelessDebugging.isEnabled()).isTrue();
    }

    @Test
    public void adbWifiDisabled_shouldReturnDisabled() {
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 0 /* setting disabled */);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_false_keyguardUnlocked_WifiDisconnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to enabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
        // Unlocked keyguard
        doReturn(false).when(mKeyguardManager).isKeyguardLocked();
        // Wifi disconnected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(false);

        mWirelessDebugging.setIsEnabled(false);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_false_keyguardLocked_WifiDisconnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to enabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
        // Locked keyguard
        doReturn(true).when(mKeyguardManager).isKeyguardLocked();
        // Wifi disconnected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(false);

        mWirelessDebugging.setIsEnabled(false);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_false_keyguardUnlocked_WifiConnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to enabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
        // Unlocked keyguard
        doReturn(false).when(mKeyguardManager).isKeyguardLocked();
        // Wifi connected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(true);

        mWirelessDebugging.setIsEnabled(false);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_false_keyguardLocked_WifiConnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to enabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
        // Locked keyguard
        doReturn(true).when(mKeyguardManager).isKeyguardLocked();
        // Wifi connected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(true);

        mWirelessDebugging.setIsEnabled(false);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_true_keyguardUnlocked_WifiDisconnected_shouldDisableAdbWifi() {
        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
        doNothing().when(mWirelessDebugging).sendBroadcast(intentCaptor.capture());
        // Precondition: set the tile to disabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 0 /* setting enabled */);
        // Unlocked keyguard
        doReturn(false).when(mKeyguardManager).isKeyguardLocked();
        // Wifi disconnected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(false);

        mWirelessDebugging.setIsEnabled(true);

        assertThat(mWirelessDebugging.isEnabled()).isFalse();
        // The notification shade should be hidden by sending a broadcast to SysUI
        // so the toast can be seen
        verify(mWirelessDebugging, times(1)).sendBroadcast(eq(intentCaptor.getValue()));
        assertThat(intentCaptor.getValue().getAction())
            .isEqualTo(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        // Should also get a toast that wifi is not connected
        verify(mToast).show();
    }

    @Test
    public void setIsEnabled_true_keyguardLocked_WifiDisconnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to disabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 0 /* setting enabled */);
        // Locked keyguard
        doReturn(true).when(mKeyguardManager).isKeyguardLocked();
        // Wifi disconnected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(false);

        mWirelessDebugging.setIsEnabled(true);

        // Shouldn't be able to enable wireless debugging from locked screen
        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }

    @Test
    public void setIsEnabled_true_keyguardUnlocked_WifiConnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to disabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 0 /* setting enabled */);
        // Unlocked keyguard
        doReturn(false).when(mKeyguardManager).isKeyguardLocked();
        // Wifi connected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(true);

        mWirelessDebugging.setIsEnabled(true);

        assertThat(mWirelessDebugging.isEnabled()).isTrue();
    }

    @Test
    public void setIsEnabled_true_keyguardLocked_WifiConnected_shouldDisableAdbWifi() {
        // Precondition: set the tile to disabled
        Global.putInt(mContext.getContentResolver(),
                Global.ADB_WIFI_ENABLED, 0 /* setting enabled */);
        // Locked keyguard
        doReturn(true).when(mKeyguardManager).isKeyguardLocked();
        // Wifi connected
        ShadowWirelessDebuggingPreferenceController.setIsWifiConnected(true);

        mWirelessDebugging.setIsEnabled(true);

        // Shouldn't be able to enable wireless debugging from locked screen
        assertThat(mWirelessDebugging.isEnabled()).isFalse();
    }
}