From 13f37337ed84082f7c2a2b49bdcc361a6ec13f3c Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Thu, 21 Feb 2019 19:41:23 +0800 Subject: [PATCH 01/17] Improve UX of Wi-Fi QR code scanner enrollee flow 1. Do not start WifiSettings after enrollee success 2. Return WifiConfiguration to the calling object after enrollee success 3. In WifiDialog, do not show scan button if Save button is not visible to users 4. Fix scanner button may not respond problem by setting listener for scanner button of ssid field and password field 5. If SSID is assigned, only allow to enrollee for the network of assigned SSID Bug: 124416152 Test: manual test Change-Id: Ic5241c4767eaa8ea01782817d8302d8b0572ab36 --- .../settings/wifi/AddNetworkFragment.java | 46 +++++++++++++++--- src/com/android/settings/wifi/WifiDialog.java | 47 ++++++++++++++----- .../settings/wifi/WifiDialogActivity.java | 27 ++++++++++- .../android/settings/wifi/WifiSettings.java | 18 ++++++- .../dpp/WifiDppQrCodeScannerFragment.java | 16 +++++-- .../settings/wifi/dpp/WifiDppUtils.java | 5 ++ .../settings/wifi/dpp/WifiNetworkConfig.java | 2 +- 7 files changed, 135 insertions(+), 26 deletions(-) diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java index 656f8efe6a4..b93a1973959 100644 --- a/src/com/android/settings/wifi/AddNetworkFragment.java +++ b/src/com/android/settings/wifi/AddNetworkFragment.java @@ -19,12 +19,14 @@ package com.android.settings.wifi; import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Intent; +import android.net.wifi.WifiConfiguration; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageButton; +import android.widget.TextView; import androidx.annotation.VisibleForTesting; @@ -40,7 +42,10 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf final static int SUBMIT_BUTTON_ID = android.R.id.button1; @VisibleForTesting final static int CANCEL_BUTTON_ID = android.R.id.button2; - final static int SCANNER_BUTTON_ID = R.id.ssid_scanner_button; + final static int SSID_SCANNER_BUTTON_ID = R.id.ssid_scanner_button; + final static int PASSWORD_SCANNER_BUTTON_ID = R.id.password_scanner_button; + + private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; private WifiConfigController mUIController; private Button mSubmitBtn; @@ -63,10 +68,12 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf mSubmitBtn = rootView.findViewById(SUBMIT_BUTTON_ID); mCancelBtn = rootView.findViewById(CANCEL_BUTTON_ID); - final ImageButton scannerButton = rootView.findViewById(SCANNER_BUTTON_ID); + final ImageButton ssidScannerButton = rootView.findViewById(SSID_SCANNER_BUTTON_ID); + final ImageButton passwordScannerButton = rootView.findViewById(PASSWORD_SCANNER_BUTTON_ID); mSubmitBtn.setOnClickListener(this); mCancelBtn.setOnClickListener(this); - scannerButton.setOnClickListener(this); + ssidScannerButton.setOnClickListener(this); + passwordScannerButton.setOnClickListener(this); mUIController = new WifiConfigController(this, rootView, null, getMode()); return rootView; @@ -80,6 +87,8 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf @Override public void onClick(View view) { + String ssid = null; + switch (view.getId()) { case SUBMIT_BUTTON_ID: handleSubmitAction(); @@ -87,14 +96,33 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf case CANCEL_BUTTON_ID: handleCancelAction(); break; - case SCANNER_BUTTON_ID: + case SSID_SCANNER_BUTTON_ID: + final TextView ssidEditText = getView().findViewById(R.id.ssid); + ssid = ssidEditText.getText().toString(); + // No break and flows to case PASSWORD_SCANNER_BUTTON_ID + case PASSWORD_SCANNER_BUTTON_ID: // Launch QR code scanner to join a network. - getContext().startActivity( - WifiDppUtils.getEnrolleeQrCodeScannerIntent(/* ssid */ null)); + startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid), + REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER); break; } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) { + if (resultCode != Activity.RESULT_OK) { + return; + } + + final WifiConfiguration config = data.getParcelableExtra( + WifiDialogActivity.KEY_WIFI_CONFIGURATION); + successfullyFinish(config); + } + } + @Override public int getMode() { return WifiConfigUiBase.MODE_CONNECT; @@ -153,9 +181,13 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf @VisibleForTesting void handleSubmitAction() { + successfullyFinish(mUIController.getConfig()); + } + + private void successfullyFinish(WifiConfiguration config) { final Intent intent = new Intent(); final Activity activity = getActivity(); - intent.putExtra(WIFI_CONFIG_KEY, mUIController.getConfig()); + intent.putExtra(WIFI_CONFIG_KEY, config); activity.setResult(Activity.RESULT_OK, intent); activity.finish(); } diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java index 7d5f3b30f4f..fbea824a00d 100644 --- a/src/com/android/settings/wifi/WifiDialog.java +++ b/src/com/android/settings/wifi/WifiDialog.java @@ -18,15 +18,16 @@ package com.android.settings.wifi; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageButton; +import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import com.android.settings.R; -import com.android.settings.wifi.dpp.WifiDppUtils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.wifi.AccessPoint; @@ -40,6 +41,9 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, default void onSubmit(WifiDialog dialog) { } + + default void onScan(WifiDialog dialog, String ssid) { + } } private static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE; @@ -80,18 +84,6 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, @Override protected void onCreate(Bundle savedInstanceState) { mView = getLayoutInflater().inflate(R.layout.wifi_dialog, /* root */ null); - final ImageButton scannerButton = mView.findViewById(R.id.password_scanner_button); - if (scannerButton != null) { - scannerButton.setOnClickListener((View v) -> { - String ssid = null; - if (mAccessPoint != null) { - ssid = mAccessPoint.getSsidStr(); - } - // Launch QR code scanner to join a network. - getContext().startActivity( - WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid)); - }); - } setView(mView); mController = new WifiConfigController(this, mView, mAccessPoint, mMode); super.onCreate(savedInstanceState); @@ -109,6 +101,35 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, } } + @Override + protected void onStart() { + View.OnClickListener onClickScannerButtonListener = v -> { + if (mListener == null) { + return; + } + + String ssid = null; + if (mAccessPoint == null) { + final TextView ssidEditText = findViewById(R.id.ssid); + ssid = ssidEditText.getText().toString(); + } else { + ssid = mAccessPoint.getSsidStr(); + } + mListener.onScan(/* WifiDialog */ this, ssid); + }; + + final ImageButton ssidScannerButton = findViewById(R.id.ssid_scanner_button); + ssidScannerButton.setOnClickListener(onClickScannerButtonListener); + + final ImageButton passwordScannerButton = findViewById(R.id.password_scanner_button); + passwordScannerButton.setOnClickListener(onClickScannerButtonListener); + + if (mHideSubmitButton) { + ssidScannerButton.setVisibility(View.GONE); + passwordScannerButton.setVisibility(View.GONE); + } + } + public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mController.updatePassword(); diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java index c32bcf3d0c6..35de66e265d 100644 --- a/src/com/android/settings/wifi/WifiDialogActivity.java +++ b/src/com/android/settings/wifi/WifiDialogActivity.java @@ -29,6 +29,7 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.SetupWizardUtils; +import com.android.settings.wifi.dpp.WifiDppUtils; import com.android.settingslib.wifi.AccessPoint; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -49,10 +50,13 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo @VisibleForTesting static final String KEY_CONNECT_FOR_CALLER = "connect_for_caller"; - private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; + public static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; + private static final int RESULT_CONNECTED = RESULT_FIRST_USER; private static final int RESULT_FORGET = RESULT_FIRST_USER + 1; + private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; + private WifiDialog mDialog; @Override @@ -162,4 +166,25 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo mDialog = null; finish(); } + + @Override + public void onScan(WifiDialog dialog, String ssid) { + // Launch QR code scanner to join a network. + startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid), + REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) { + if (resultCode != RESULT_OK) { + return; + } + + setResult(RESULT_CONNECTED, data); + finish(); + } + } } diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 4ca9f8680c0..27c495ed3db 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -117,6 +117,8 @@ public class WifiSettings extends RestrictedSettingsFragment private static final String PREF_KEY_SAVED_NETWORKS = "saved_networks"; private static final String PREF_KEY_STATUS_MESSAGE = "wifi_status_message"; + private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; + private static boolean isVerboseLoggingEnabled() { return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE); } @@ -427,10 +429,17 @@ public class WifiSettings extends RestrictedSettingsFragment public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - // Only handle request comes from AddNetworkFragment if (requestCode == ADD_NETWORK_REQUEST) { handleAddNetworkRequest(resultCode, data); return; + } else if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) { + if (resultCode == Activity.RESULT_OK) { + if (mDialog != null) { + mDialog.dismiss(); + } + mWifiTracker.resumeScanning(); + } + return; } final boolean formerlyRestricted = mIsRestricted; @@ -1065,6 +1074,13 @@ public class WifiSettings extends RestrictedSettingsFragment } } + @Override + public void onScan(WifiDialog dialog, String ssid) { + // Launch QR code scanner to join a network. + startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid), + REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER); + } + /* package */ void submit(WifiConfigController configController) { final WifiConfiguration config = configController.getConfig(); diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java index c88313b84e8..9af559a6b4f 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java @@ -31,7 +31,6 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.Size; @@ -47,6 +46,7 @@ import android.widget.TextView; import androidx.lifecycle.ViewModelProviders; import com.android.settings.R; +import com.android.settings.wifi.WifiDialogActivity; import com.android.settings.wifi.qrcode.QrCamera; import com.android.settings.wifi.qrcode.QrDecorateView; @@ -76,6 +76,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl // Key for Bundle usage private static final String KEY_IS_CONFIGURATOR_MODE = "key_is_configurator_mode"; private static final String KEY_LATEST_ERROR_CODE = "key_latest_error_code"; + private static final String KEY_WIFI_CONFIGURATION = "key_wifi_configuration"; private QrCamera mCamera; private TextureView mTextureView; @@ -91,6 +92,9 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl /** QR code data scanned by camera */ private WifiQrCode mWifiQrCode; + /** The WifiConfiguration connecting for enrollee usage */ + private WifiConfiguration mWifiConfiguration; + private int mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_FAILURE_NONE; @Override @@ -100,6 +104,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl if (savedInstanceState != null) { mIsConfiguratorMode = savedInstanceState.getBoolean(KEY_IS_CONFIGURATOR_MODE); mLatestStatusCode = savedInstanceState.getInt(KEY_LATEST_ERROR_CODE); + mWifiConfiguration = savedInstanceState.getParcelable(KEY_WIFI_CONFIGURATION); } final WifiDppInitiatorViewModel model = @@ -410,6 +415,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl mErrorMessage.setVisibility(View.INVISIBLE); final WifiNetworkConfig wifiNetworkConfig = (WifiNetworkConfig)msg.obj; + mWifiConfiguration = wifiNetworkConfig.getWifiConfigurationOrNull(); wifiNetworkConfig.connect(getContext(), /* listener */ WifiDppQrCodeScannerFragment.this); break; @@ -424,6 +430,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl public void onSaveInstanceState(Bundle outState) { outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode); outState.putInt(KEY_LATEST_ERROR_CODE, mLatestStatusCode); + outState.putParcelable(KEY_WIFI_CONFIGURATION, mWifiConfiguration); super.onSaveInstanceState(outState); } @@ -439,6 +446,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl for (WifiConfiguration wifiConfig : wifiConfigs) { if (wifiConfig.networkId == newNetworkId) { mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_SUCCESS; + mWifiConfiguration = wifiConfig; wifiManager.connect(wifiConfig, WifiDppQrCodeScannerFragment.this); return; } @@ -530,9 +538,11 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl @Override public void onSuccess() { - startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); + final Intent resultIntent = new Intent(); + resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION, mWifiConfiguration); + final Activity hostActivity = getActivity(); - hostActivity.setResult(Activity.RESULT_OK); + hostActivity.setResult(Activity.RESULT_OK, resultIntent); hostActivity.finish(); } diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java index 24cd1d75a63..6c991cffdbe 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java +++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java @@ -95,6 +95,11 @@ public class WifiDppUtils { /** * Returns an intent to launch QR code scanner for Wi-Fi DPP enrollee. * + * After enrollee success, the callee activity will return connecting WifiConfiguration by + * putExtra {@code WifiDialogActivity.KEY_WIFI_CONFIGURATION} for + * {@code Activity#setResult(int resultCode, Intent data)}. The calling object should check + * if it's available before using it. + * * @param ssid The data corresponding to {@code WifiConfiguration} SSID * @return Intent for launching QR code scanner */ diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java index 979e602bf4a..6135cba190e 100644 --- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java +++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java @@ -228,7 +228,7 @@ public class WifiNetworkConfig { /** * This is a simplified method from {@code WifiConfigController.getConfig()} */ - private WifiConfiguration getWifiConfigurationOrNull() { + WifiConfiguration getWifiConfigurationOrNull() { if (!isValidConfig(this)) { return null; } From 957ce7f7aa753b37cd3ca4be5f85dfbaad7c5af4 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 25 Feb 2019 15:05:52 +0800 Subject: [PATCH 02/17] Update strings for Wi-Fi DPP handshake running state Bug: 125987679 Test: manual test Change-Id: I55eddee5f3c0c28d1be23b5b9d8c0b56280be797 --- res/values/strings.xml | 4 +++ .../wifi/dpp/WifiDppAddDeviceFragment.java | 14 ++++++++++- .../dpp/WifiDppQrCodeScannerFragment.java | 25 +++++++++++++------ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index f5811210e7a..6a244b53187 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2153,6 +2153,10 @@ Couldn\u2019t add device Device found + + Sharing Wi\u2011Fi with this device\u2026 + + Connecting\u2026 Retry diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java index 97b2ebefc8f..9e731ba7936 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java @@ -172,6 +172,9 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment { mLatestStatusCode = code; } + if (isGoingInitiator()) { + mSummary.setText(R.string.wifi_dpp_sharing_wifi_with_this_device); + } mProgressBar.setVisibility(isGoingInitiator() ? View.VISIBLE : View.INVISIBLE); mButtonRight.setVisibility(isGoingInitiator() ? View.INVISIBLE : View.VISIBLE); } @@ -255,7 +258,7 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment { mTitle.setText(information); } - mSummary.setText(getString(R.string.wifi_dpp_add_device_to_wifi, getSsid())); + updateSummary(); mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view); mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network); @@ -273,6 +276,7 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment { mProgressBar.setVisibility(View.VISIBLE); mButtonRight.setVisibility(View.INVISIBLE); startWifiDppConfiguratorInitiator(); + updateSummary(); }); if (savedInstanceState != null) { @@ -342,4 +346,12 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment { return model.isGoingInitiator(); } + + private void updateSummary() { + if (isGoingInitiator()) { + mSummary.setText(R.string.wifi_dpp_sharing_wifi_with_this_device); + } else { + mSummary.setText(getString(R.string.wifi_dpp_add_device_to_wifi, getSsid())); + } + } } diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java index e664a0508e7..d432d7c113c 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java @@ -224,13 +224,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl } else { mTitle.setText(R.string.wifi_dpp_scan_qr_code); - String description; - if (TextUtils.isEmpty(mSsid)) { - description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid); - } else { - description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid); - } - mSummary.setText(description); + updateEnrolleeSummary(); } mErrorMessage = view.findViewById(R.id.error_message); @@ -410,6 +404,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl if (!mIsConfiguratorMode) { mProgressBar.setVisibility(View.VISIBLE); startWifiDppEnrolleeInitiator((WifiQrCode)msg.obj); + updateEnrolleeSummary(); } break; @@ -453,6 +448,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl Log.e(TAG, "Invalid networkId " + newNetworkId); mLatestStatusCode = EasyConnectStatusCallback.EASY_CONNECT_EVENT_FAILURE_GENERIC; + updateEnrolleeSummary(); mProgressBar.setVisibility(View.INVISIBLE); showErrorMessage(getString(R.string.wifi_dpp_check_connection_try_again)); restartCamera(); @@ -520,6 +516,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl } mLatestStatusCode = code; + updateEnrolleeSummary(); mProgressBar.setVisibility(View.INVISIBLE); restartCamera(); } @@ -578,4 +575,18 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl mCamera.start(surfaceTexture); } + + private void updateEnrolleeSummary() { + if (isGoingInitiator()) { + mSummary.setText(R.string.wifi_dpp_connecting); + } else { + String description; + if (TextUtils.isEmpty(mSsid)) { + description = getString(R.string.wifi_dpp_scan_qr_code_join_unknown_network, mSsid); + } else { + description = getString(R.string.wifi_dpp_scan_qr_code_join_network, mSsid); + } + mSummary.setText(description); + } + } } From f51826853b0920150a9044952bb3dde8a2965224 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 4 Feb 2019 17:36:23 -0800 Subject: [PATCH 03/17] Add additional anomaly types. Test: Treehugger Bug: 115540658 Change-Id: I369f5bfadfe10810aa33d4127fb9ce69c9c57e7e --- .../batterytip/StatsManagerConfig.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java b/src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java index 4a0b5ba01fb..d7bde786c92 100644 --- a/src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java +++ b/src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java @@ -68,6 +68,11 @@ public class StatsManagerConfig { AnomalyType.EXCESSIVE_CRASH_RATE, AnomalyType.EXCESSIVE_CRASH_LOOPING, AnomalyType.NUMBER_OF_OPEN_FILES, + AnomalyType.EXCESSIVE_CAMERA_USAGE_IN_BACKGROUND, + AnomalyType.EXCESSIVE_CONTACT_ACCESS, + AnomalyType.EXCESSIVE_AUDIO_IN_BACKGROUND, + AnomalyType.EXCESSIVE_CRASH_ANR_IN_BACKGROUND, + AnomalyType.BATTERY_DRAIN_FROM_UNUSED_APP, }) public @interface AnomalyType { /** @@ -221,6 +226,42 @@ public class StatsManagerConfig { * The application crashed because no more file descriptors were available. */ int NUMBER_OF_OPEN_FILES = 26; + + /** + * The application used an excessive amount of CPU while in a + * background process state. + */ + int EXCESSIVE_CPU_USAGE_IN_BACKGROUND = 27; + + /** + * The application kept the camera open for an excessive amount + * of time while in a bckground process state. + */ + int EXCESSIVE_CAMERA_USAGE_IN_BACKGROUND = 28; + + /** + * The application has accessed the contacts content provider an + * excessive amount. + */ + int EXCESSIVE_CONTACT_ACCESS = 29; + + /** + * The application has played too much audio while in a background + * process state. + */ + int EXCESSIVE_AUDIO_IN_BACKGROUND = 30; + + /** + * The application has crashed or ANRed too many times while in a + * background process state. + */ + int EXCESSIVE_CRASH_ANR_IN_BACKGROUND = 31; + + /** + * An application which has not been used by the user recently + * was detected to cause an excessive amount of battery drain. + */ + int BATTERY_DRAIN_FROM_UNUSED_APP = 32; } } From d565d7a505e1d7816baadecde353b99c8e973d72 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Mon, 25 Feb 2019 15:52:40 -0500 Subject: [PATCH 04/17] Add summary to Notification Assistant picker Test: manual Test: atest Fixes: 126200103 Change-Id: I9569ca7dd58184242fe740e3db63bd7958042cfb --- ...ficationAssistantPreferenceController.java | 28 +++++ ...tionAssistantPreferenceControllerTest.java | 100 ++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java index 5c591b894ac..66f27fef953 100644 --- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java +++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java @@ -16,18 +16,46 @@ package com.android.settings.notification; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; +import android.os.UserHandle; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.applications.DefaultAppInfo; +import com.android.settingslib.widget.CandidateInfo; + +import com.google.common.annotations.VisibleForTesting; public class NotificationAssistantPreferenceController extends BasePreferenceController { + @VisibleForTesting + protected NotificationBackend mNotificationBackend; + private PackageManager mPackageManager; + public NotificationAssistantPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); + mNotificationBackend = new NotificationBackend(); + mPackageManager = mContext.getPackageManager(); } @Override public int getAvailabilityStatus() { return BasePreferenceController.AVAILABLE; } + + @Override + public CharSequence getSummary() { + CandidateInfo appSelected = new NotificationAssistantPicker.CandidateNone(mContext); + ComponentName assistant = mNotificationBackend.getAllowedNotificationAssistant(); + if (assistant != null) { + appSelected = createCandidateInfo(assistant); + } + return appSelected.loadLabel(); + } + + @VisibleForTesting + protected CandidateInfo createCandidateInfo(ComponentName cn) { + return new DefaultAppInfo(mContext, mPackageManager, UserHandle.myUserId(), cn); + } } diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java new file mode 100644 index 00000000000..b2f65e06d7b --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2019 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.notification; + +import static junit.framework.TestCase.assertEquals; + +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Debug; + +import com.android.settingslib.widget.CandidateInfo; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class NotificationAssistantPreferenceControllerTest { + + private static final String KEY = "TEST_KEY"; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private NotificationBackend mBackend; + private NotificationAssistantPreferenceController mPreferenceController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mPreferenceController = new TestPreferenceController(mContext, mBackend); + } + + @Test + public void testGetSummary_noAssistant() { + when(mBackend.getAllowedNotificationAssistant()).thenReturn(null); + CharSequence noneLabel = new NotificationAssistantPicker.CandidateNone(mContext) + .loadLabel(); + assertEquals(noneLabel, mPreferenceController.getSummary()); + } + + @Test + public void testGetSummary_TestAssistant() { + String testName = "test_pkg/test_cls"; + when(mBackend.getAllowedNotificationAssistant()).thenReturn( + ComponentName.unflattenFromString(testName)); + assertEquals(testName, mPreferenceController.getSummary()); + } + + private final class TestPreferenceController extends NotificationAssistantPreferenceController { + + private TestPreferenceController(Context context, NotificationBackend backend) { + super(context, KEY); + mNotificationBackend = backend; + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + protected CandidateInfo createCandidateInfo(ComponentName cn) { + return new CandidateInfo(true) { + @Override + public CharSequence loadLabel() { return cn.flattenToString(); } + + @Override + public Drawable loadIcon() { return null; } + + @Override + public String getKey() { return null; } + }; + } + } + +} From 986f2ecc55b2b40f04c4508e8eb160f5894bc96f Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 21 Feb 2019 10:53:48 -0500 Subject: [PATCH 05/17] Make PreventRingingSwitch preference clickable - Talk back says the preference is clickable Test: make ROBOTEST_FILTER=PreventRingingSwitchPreferenceControllerTest RunSettingsRoboTests -j40 Bug: 124827588 Change-Id: Ia409bbc6516f6aa11975726691131f1fad1518fd --- .../PreventRingingSwitchPreferenceController.java | 11 +++++++++++ ...ventRingingSwitchPreferenceControllerTest.java | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java index 35ff2ec5cf4..e21bb7563bf 100644 --- a/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java +++ b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java @@ -61,6 +61,17 @@ public class PreventRingingSwitchPreferenceController extends AbstractPreference LayoutPreference pref = screen.findPreference(getPreferenceKey()); if (pref != null) { mSettingObserver = new SettingObserver(pref); + pref.setOnPreferenceClickListener(preference -> { + int preventRinging = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.VOLUME_HUSH_GESTURE, + Settings.Secure.VOLUME_HUSH_VIBRATE); + boolean isChecked = preventRinging != Settings.Secure.VOLUME_HUSH_OFF; + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.VOLUME_HUSH_GESTURE, isChecked + ? Settings.Secure.VOLUME_HUSH_OFF + : Settings.Secure.VOLUME_HUSH_VIBRATE); + return true; + }); mSwitch = pref.findViewById(R.id.switch_bar); if (mSwitch != null) { mSwitch.addOnSwitchChangeListener(this); diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java index 5f221f578f7..85eeacc4ce2 100644 --- a/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java @@ -18,6 +18,7 @@ package com.android.settings.gestures; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -29,8 +30,10 @@ import android.content.res.Resources; import android.provider.Settings; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.widget.LayoutPreference; import org.junit.Before; import org.junit.Test; @@ -95,4 +98,16 @@ public class PreventRingingSwitchPreferenceControllerTest { mController.updateState(mPreference); verify(mController.mSwitch, times(1)).setChecked(true); } + + @Test + public void testPreferenceClickListenerAttached() { + PreferenceScreen preferenceScreen = mock(PreferenceScreen.class); + LayoutPreference mLayoutPreference = mock(LayoutPreference.class); + when(preferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn( + mLayoutPreference); + mController.displayPreference(preferenceScreen); + + verify(mLayoutPreference, times(1)) + .setOnPreferenceClickListener(any()); + } } From 0047944c2e7a6cfd8b98e748857707bd9edaec10 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 25 Feb 2019 16:05:36 -0800 Subject: [PATCH 06/17] Clean up instrumentation tests - Fixed some important tests - Deleted some useless tests - Some tests are still broken, filed bugs for these Fixes: 124572765 Test: atest Change-Id: Iac4e6a1fb1dbf9383d91945525df69a651ae77fd --- .../android/settings/DisplaySettingsTest.java | 59 -------- .../settings/EncryptionInterstitialTest.java | 110 -------------- .../ManagedAccessSettingsLowRamTest.java | 126 ---------------- .../RegulatoryInfoDisplayActivityTest.java | 81 ---------- .../android/settings/SettingsHookTests.java | 130 ---------------- ...ibilityShortcutPreferenceFragmentTest.java | 17 +-- .../applications/DefaultAppSettingsTest.java | 79 ---------- .../ManageApplicationsLaunchTest.java | 58 -------- .../SpecialAppAccessSettingsTest.java | 97 ------------ .../settings/backup/BackupIntentTest.java | 2 +- .../BluetoothDeviceDetailsRotationTest.java | 106 ------------- .../bluetooth/DevicePickerActivityTest.java | 47 ------ .../ConnectedDeviceActivityTest.java | 68 --------- .../dashboard/PreferenceThemeTest.java | 18 --- .../MobileDataUsageActivityTest.java | 64 -------- .../timezone/model/TimeZoneDataTest.java | 3 - .../StorageDashboardFragmentTest.java | 41 ----- .../dream/DreamSettingsLaunchTest.java | 41 ----- .../tests/DrawOverlayDetailsTest.java | 77 ---------- .../settings/tests/KeepOnScreenTest.java | 72 --------- .../tests/PrivateVolumeSettingsTest.java | 42 ------ .../tests/SettingsRestoreAfterCloseTest.java | 84 ----------- .../settings/users/UserSettingsTest.java | 140 ------------------ .../wifi/tether/WifiTetherSettingsTest.java | 4 +- 24 files changed, 4 insertions(+), 1562 deletions(-) delete mode 100644 tests/unit/src/com/android/settings/DisplaySettingsTest.java delete mode 100644 tests/unit/src/com/android/settings/EncryptionInterstitialTest.java delete mode 100644 tests/unit/src/com/android/settings/ManagedAccessSettingsLowRamTest.java delete mode 100644 tests/unit/src/com/android/settings/SettingsHookTests.java delete mode 100644 tests/unit/src/com/android/settings/applications/DefaultAppSettingsTest.java delete mode 100644 tests/unit/src/com/android/settings/applications/ManageApplicationsLaunchTest.java delete mode 100644 tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java delete mode 100644 tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java delete mode 100644 tests/unit/src/com/android/settings/bluetooth/DevicePickerActivityTest.java delete mode 100644 tests/unit/src/com/android/settings/connecteddevice/ConnectedDeviceActivityTest.java delete mode 100644 tests/unit/src/com/android/settings/datausage/MobileDataUsageActivityTest.java delete mode 100644 tests/unit/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java delete mode 100644 tests/unit/src/com/android/settings/dream/DreamSettingsLaunchTest.java delete mode 100644 tests/unit/src/com/android/settings/tests/DrawOverlayDetailsTest.java delete mode 100644 tests/unit/src/com/android/settings/tests/KeepOnScreenTest.java delete mode 100644 tests/unit/src/com/android/settings/tests/PrivateVolumeSettingsTest.java delete mode 100644 tests/unit/src/com/android/settings/tests/SettingsRestoreAfterCloseTest.java delete mode 100644 tests/unit/src/com/android/settings/users/UserSettingsTest.java diff --git a/tests/unit/src/com/android/settings/DisplaySettingsTest.java b/tests/unit/src/com/android/settings/DisplaySettingsTest.java deleted file mode 100644 index cc9cd819319..00000000000 --- a/tests/unit/src/com/android/settings/DisplaySettingsTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.support.test.uiautomator.UiDevice; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class DisplaySettingsTest { - - private Instrumentation mInstrumentation; - private Context mContext; - private UiDevice mDevice; - - @Before - public void setUp() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mContext = mInstrumentation.getTargetContext(); - mDevice = UiDevice.getInstance(mInstrumentation); - } - - @Test - public void launchBrightnessLevel_shouldNotCrash() { - mInstrumentation.startActivitySync( - new Intent(mContext, DisplaySettings.class)); - onView(withText(mContext.getString(R.string.brightness))).perform(click()); - // should not crash - mDevice.pressBack(); // dismiss the brightness dialog - } -} diff --git a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java b/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java deleted file mode 100644 index 503a78c6bb8..00000000000 --- a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.withId; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.app.Activity; -import android.app.Instrumentation; -import android.app.Instrumentation.ActivityMonitor; -import android.app.Instrumentation.ActivityResult; -import android.content.Context; -import android.content.Intent; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; - -import com.google.android.setupcompat.PartnerCustomizationLayout; -import com.google.android.setupcompat.template.FooterBarMixin; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@MediumTest -public class EncryptionInterstitialTest { - - private Instrumentation mInstrumentation; - private Context mContext; - private TestActivityMonitor mActivityMonitor; - - @Before - public void setUp() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mContext = mInstrumentation.getTargetContext(); - mActivityMonitor = new TestActivityMonitor(); - mInstrumentation.addMonitor(mActivityMonitor); - } - - @After - public void tearDown() { - mInstrumentation.removeMonitor(mActivityMonitor); - } - - @Test - public void clickYes_shouldRequirePassword() { - final Activity activity = mInstrumentation.startActivitySync( - new Intent(mContext, EncryptionInterstitial.class) - .putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent"))); - final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout); - layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick(); - - mActivityMonitor.waitForActivityWithTimeout(1000); - assertEquals(1, mActivityMonitor.getHits()); - - assertTrue(mActivityMonitor.mMatchedIntent.getBooleanExtra( - EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false)); - } - - @Test - public void clickNo_shouldNotRequirePassword() { - final Activity activity = mInstrumentation.startActivitySync( - new Intent(mContext, EncryptionInterstitial.class) - .putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent"))); - final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout); - layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().performClick(); - - mActivityMonitor.waitForActivityWithTimeout(1000); - assertEquals(1, mActivityMonitor.getHits()); - - assertFalse(mActivityMonitor.mMatchedIntent.getBooleanExtra( - EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true)); - } - - private static class TestActivityMonitor extends ActivityMonitor { - - Intent mMatchedIntent = null; - - @Override - public ActivityResult onStartActivity(Intent intent) { - if ("test.unlock.intent".equals(intent.getAction())) { - mMatchedIntent = intent; - return new ActivityResult(Activity.RESULT_OK, null); - } - return null; - } - } -} diff --git a/tests/unit/src/com/android/settings/ManagedAccessSettingsLowRamTest.java b/tests/unit/src/com/android/settings/ManagedAccessSettingsLowRamTest.java deleted file mode 100644 index 426b8a4270b..00000000000 --- a/tests/unit/src/com/android/settings/ManagedAccessSettingsLowRamTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.ActivityManager; -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.provider.Settings; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class ManagedAccessSettingsLowRamTest { - - private Instrumentation mInstrumentation; - private Context mTargetContext; - - @Before - public void setUp() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mTargetContext = mInstrumentation.getTargetContext(); - } - - @Test - public void testManagedAccessOptionsVisibility() throws Exception { - mInstrumentation.startActivitySync(new Intent(mTargetContext, - com.android.settings.Settings.AppAndNotificationDashboardActivity.class)); - onView(withText(mTargetContext.getString(R.string.expand_button_title))).perform(click()); - onView(withText(mTargetContext.getString(R.string.special_access))).perform(click()); - - String[] managedServiceLabels = new String[] {"Do Not Disturb access", - "VR helper services", "Notification access", "Picture-in-picture"}; - for (String label : managedServiceLabels) { - if (ActivityManager.isLowRamDeviceStatic()) { - onView(withText(label)).check(doesNotExist()); - } else { - onView(withText(label)).check(matches(isDisplayed())); - } - } - } - - @Test - public void launchNotificationSetting_onlyWorksIfNotLowRam() { - final Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); - - mInstrumentation.startActivitySync(intent); - - final String label = "This feature is not available on this device"; - if (ActivityManager.isLowRamDeviceStatic()) { - onView(withText(label)).check(matches(isDisplayed())); - } else { - onView(withText(label)).check(doesNotExist()); - } - } - - @Test - public void launchDndSetting_onlyWorksIfNotLowRam() { - final Intent intent = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); - - mInstrumentation.startActivitySync(intent); - - final String label = "This feature is not available on this device"; - if (ActivityManager.isLowRamDeviceStatic()) { - onView(withText(label)).check(matches(isDisplayed())); - } else { - onView(withText(label)).check(doesNotExist()); - } - } - - @Test - public void launchVrSetting_onlyWorksIfNotLowRam() { - final Intent intent = new Intent(Settings.ACTION_VR_LISTENER_SETTINGS); - - mInstrumentation.startActivitySync(intent); - - final String label = "This feature is not available on this device"; - if (ActivityManager.isLowRamDeviceStatic()) { - onView(withText(label)).check(matches(isDisplayed())); - } else { - onView(withText(label)).check(doesNotExist()); - } - } - - @Test - public void launchPictureInPictureSetting_onlyWorksIfNotLowRam() { - final Intent intent = new Intent(Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS); - - mInstrumentation.startActivitySync(intent); - - final String label = "This feature is not available on this device"; - if (ActivityManager.isLowRamDeviceStatic()) { - onView(withText(label)).check(matches(isDisplayed())); - } else { - onView(withText(label)).check(doesNotExist()); - } - } -} diff --git a/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java b/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java index 48f9f5d53f4..1701ddff900 100644 --- a/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java +++ b/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java @@ -16,12 +16,6 @@ package com.android.settings; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.RootMatchers.isDialog; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; - import static junit.framework.Assert.fail; import android.app.Instrumentation; @@ -29,8 +23,6 @@ import android.app.UiAutomation; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -import android.graphics.Bitmap; -import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -40,10 +32,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - @RunWith(AndroidJUnit4.class) @SmallTest public class RegulatoryInfoDisplayActivityTest { @@ -82,73 +70,4 @@ public class RegulatoryInfoDisplayActivityTest { return; } } - - @Test - public void launchRegulatoryInfo_shouldNotCrash() { - final Context context = mInstrumentation.getTargetContext(); - final boolean hasRegulatoryInfo = context.getResources() - .getBoolean(R.bool.config_show_regulatory_info); - - if (!hasRegulatoryInfo) { - return; - } - // Launch intent - mInstrumentation.startActivitySync(mRegulatoryInfoIntent); - - onView(withId(R.id.regulatoryInfo)) - .inRoot(isDialog()) - .check(matches(isDisplayed())); - } - - @Test - public void launchRegulatoryInfo_withInfoImage_shouldDisplay() throws IOException { - // TODO: Remove "setenforce 0" when selinux rules is updated to give read permission for - // regulatory info. - mUiAutomation.executeShellCommand("setenforce 0"); - - final boolean tempFileCreated = ensureRegulatoryInfoImageExists(); - try { - final Context context = mInstrumentation.getTargetContext(); - final boolean hasRegulatoryInfo = context.getResources() - .getBoolean(R.bool.config_show_regulatory_info); - - if (!hasRegulatoryInfo) { - return; - } - // Launch intent - mInstrumentation.startActivitySync(mRegulatoryInfoIntent); - - onView(withId(R.id.regulatoryInfo)) - .inRoot(isDialog()) - .check(matches(isDisplayed())); - } finally { - if (tempFileCreated) { - final String filename = - RegulatoryInfoDisplayActivity.getRegulatoryInfoImageFileName(); - new File(filename).delete(); - Log.d(TAG, "Deleting temp file " + filename); - } - } - } - - /** - * Ensures regulatory label image exists on disk. - * - * @return true if a test image is created. - */ - private boolean ensureRegulatoryInfoImageExists() throws IOException { - final String filename = RegulatoryInfoDisplayActivity.getRegulatoryInfoImageFileName(); - if (new File(filename).exists()) { - return false; - } - Log.d(TAG, "Creating temp file " + filename); - final Bitmap bitmap = Bitmap.createBitmap(400 /* width */, 400 /* height */, - Bitmap.Config.ARGB_8888); - final FileOutputStream out = new FileOutputStream(filename); - bitmap.compress(Bitmap.CompressFormat.PNG, 100 /* quality */, out); - out.close(); - return true; - } - - } diff --git a/tests/unit/src/com/android/settings/SettingsHookTests.java b/tests/unit/src/com/android/settings/SettingsHookTests.java deleted file mode 100644 index ee0bbb6e076..00000000000 --- a/tests/unit/src/com/android/settings/SettingsHookTests.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2010 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; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.test.ActivityInstrumentationTestCase2; - -import java.util.List; - -/** - * Tests for the Settings operator/manufacturer hook. - * - * Running all tests: - * - * make SettingsTests - * adb push SettingsTests.apk /system/app/SettingsTests.apk - * adb shell am instrument \ - * -w com.android.settings.tests/android.test.InstrumentationTestRunner - */ -public class SettingsHookTests extends ActivityInstrumentationTestCase2 { - - private static final String PACKAGE_NAME = "com.android.settings.tests.unit"; - - private static final String KEY_SETTINGS_ROOT = "parent"; - private static final String KEY_SETTINGS_OPERATOR = "operator_settings"; - private static final String KEY_SETTINGS_MANUFACTURER = "manufacturer_settings"; - - private static final String INTENT_OPERATOR_HOOK = "com.android.settings.OPERATOR_APPLICATION_SETTING"; - private static final String INTENT_MANUFACTURER_HOOK = "com.android.settings.MANUFACTURER_APPLICATION_SETTING"; - - private Settings mSettings; - - public SettingsHookTests() { - super("com.android.settings", Settings.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - mSettings = getActivity(); - } - - /** - * Test that the operator/manufacturer settings hook test application is - * available and that it's installed in the device's system image. - */ - public void testSettingsHookTestAppAvailable() throws Exception { - Context context = mSettings.getApplicationContext(); - PackageManager pm = context.getPackageManager(); - ApplicationInfo applicationInfo = pm.getApplicationInfo(PACKAGE_NAME, 0); - assertTrue((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); - } - - /** - * Test that the operator test activity has registered an intent-filter for - * an action named 'android.settings.OPERATOR_APPLICATION_SETTING'. - */ - public void testOperatorIntentFilter() { - boolean result = false; - Context context = mSettings.getApplicationContext(); - PackageManager pm = context.getPackageManager(); - Intent intent = new Intent(INTENT_OPERATOR_HOOK); - List list = pm.queryIntentActivities(intent, 0); - for (ResolveInfo resolveInfo : list) { - if (resolveInfo.activityInfo.packageName.equals(PACKAGE_NAME)) { - result = true; - } - } - assertTrue("Intent-filter not found", result); - } - - /** - * Test that the manufacturer test activity has registered an intent-filter - * for an action named 'android.settings.MANUFACTURER_APPLICATION_SETTING'. - */ - public void testManufacturerIntentFilter() { - boolean result = false; - Context context = mSettings.getApplicationContext(); - PackageManager pm = context.getPackageManager(); - Intent intent = new Intent(INTENT_MANUFACTURER_HOOK); - List list = pm.queryIntentActivities(intent, 0); - for (ResolveInfo resolveInfo : list) { - if (resolveInfo.activityInfo.packageName.equals(PACKAGE_NAME)) { - result = true; - } - } - assertTrue("Intent-filter not found", result); - } - - /** - * Test that the operator preference is available in the Settings - * application. - */ - public void testOperatorPreferenceAvailable() { -// TODO: fix this test case to work with fragments -// PreferenceGroup root = (PreferenceGroup)mSettings.findPreference(KEY_SETTINGS_ROOT); -// Preference operatorPreference = root.findPreference(KEY_SETTINGS_OPERATOR); -// assertNotNull(operatorPreference); - } - - /** - * Test that the manufacturer preference is available in the Settings - * application. - */ - public void testManufacturerPreferenceAvailable() { -// TODO: fix this test case to work with fragments -// PreferenceGroup root = (PreferenceGroup)mSettings.findPreference(KEY_SETTINGS_ROOT); -// Preference manufacturerHook = root.findPreference(KEY_SETTINGS_MANUFACTURER); -// assertNotNull(manufacturerHook); - } - -} diff --git a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java index f8d06a8a83d..0c27379a0fd 100644 --- a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java +++ b/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java @@ -30,6 +30,7 @@ import static org.hamcrest.Matchers.allOf; import android.app.Instrumentation; import android.os.Bundle; + import android.provider.Settings; import android.widget.CompoundButton; @@ -63,14 +64,6 @@ public class AccessibilityShortcutPreferenceFragmentTest { mActivity = mActivityRule.getActivity(); } - @Test - public void lockScreenPreference_defaultBeforeDialogShown_isOff() { - setDialogShown(false); - setOnLockscreen(null); - startFragment(); - assertLockscreenSwitchIsCheckedIs(false); - } - @Test public void lockScreenPreference_setOnBeforeDialogShown_isOn() { setDialogShown(false); @@ -87,14 +80,6 @@ public class AccessibilityShortcutPreferenceFragmentTest { assertLockscreenSwitchIsCheckedIs(true); } - @Test - public void lockScreenPreference_setOffAfterDialogShown_isOn() { - setDialogShown(true); - setOnLockscreen(false); - startFragment(); - assertLockscreenSwitchIsCheckedIs(false); - } - private void startFragment() { mInstrumentation.runOnMainSync(() -> { new SubSettingLauncher(mActivity) diff --git a/tests/unit/src/com/android/settings/applications/DefaultAppSettingsTest.java b/tests/unit/src/com/android/settings/applications/DefaultAppSettingsTest.java deleted file mode 100644 index 1dd899eb7e2..00000000000 --- a/tests/unit/src/com/android/settings/applications/DefaultAppSettingsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.applications; - -import android.content.Context; -import android.content.Intent; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiSelector; -import android.test.InstrumentationTestCase; -import android.widget.TextView; - -import androidx.test.filters.SmallTest; - -import com.android.settings.R; - -import org.junit.Test; - -/** - * Test for Advanced App preferences. - */ -@SmallTest -public class DefaultAppSettingsTest extends InstrumentationTestCase { - - private UiDevice mDevice; - private Context mTargetContext; - private String mTargetPackage; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mDevice = UiDevice.getInstance(getInstrumentation()); - mTargetContext = getInstrumentation().getTargetContext(); - mTargetPackage = mTargetContext.getPackageName(); - } - - @Test - public void testSelectDefaultHome_shouldLaunchHomePicker() throws Exception { - launchDefaultApps(); - final String titleHomeApp = mTargetContext.getResources().getString(R.string.home_app); - mDevice.findObject(new UiSelector().text(titleHomeApp)).click(); - final UiObject actionBar = mDevice.findObject(new UiSelector().resourceId( - "com.android.settings:id/action_bar")); - final UiObject title = actionBar.getChild( - new UiSelector().className(TextView.class.getName())); - assertEquals(titleHomeApp, title.getText()); - } - - private void launchDefaultApps() throws Exception { - final Intent settingsIntent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setPackage(mTargetPackage) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getInstrumentation().getContext().startActivity(settingsIntent); - final String titleApps = mTargetContext.getResources().getString( - R.string.app_and_notification_dashboard_title); - mDevice.findObject(new UiSelector().text(titleApps)).click(); - final String titleAdvance = mTargetContext.getResources().getString( - R.string.advanced_section_header); - mDevice.findObject(new UiSelector().text(titleAdvance)).click(); - final String titleDefaultApps = mTargetContext.getResources().getString( - R.string.app_default_dashboard_title); - mDevice.findObject(new UiSelector().text(titleDefaultApps)).click(); - } - -} diff --git a/tests/unit/src/com/android/settings/applications/ManageApplicationsLaunchTest.java b/tests/unit/src/com/android/settings/applications/ManageApplicationsLaunchTest.java deleted file mode 100644 index c98a43d5c84..00000000000 --- a/tests/unit/src/com/android/settings/applications/ManageApplicationsLaunchTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.applications; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.hamcrest.Matchers.allOf; - -import android.app.Instrumentation; -import android.content.Intent; -import android.provider.Settings; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class ManageApplicationsLaunchTest { - - private Instrumentation mInstrumentation; - - @Before - public void setUp() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - } - - @Test - public void launchAppsSettings_shouldShowAppList() throws Exception { - final Intent appsSettingsIntent = new - Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS); - - mInstrumentation.startActivitySync(appsSettingsIntent); - - onView(allOf(withText("Calculator"))).check(matches(isDisplayed())); - } -} diff --git a/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java b/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java deleted file mode 100644 index 4738d594a0f..00000000000 --- a/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.applications; - -import android.content.Context; -import android.content.Intent; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiScrollable; -import android.support.test.uiautomator.UiSelector; -import android.test.InstrumentationTestCase; -import android.widget.TextView; - -import androidx.test.filters.SmallTest; - -import com.android.settings.R; - -import org.junit.Test; - -/** - * Test for Special App Access preferences. - */ -@SmallTest -public class SpecialAppAccessSettingsTest extends InstrumentationTestCase { - - private UiDevice mDevice; - private Context mTargetContext; - private String mTargetPackage; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mDevice = UiDevice.getInstance(getInstrumentation()); - mTargetContext = getInstrumentation().getTargetContext(); - mTargetPackage = mTargetContext.getPackageName(); - } - - @Test - public void testSelectPictureInPicture_shouldNotCrash() throws Exception { - launchSpecialApps(); - final String titlePictureInPictureApp = - mTargetContext.getResources().getString(R.string.picture_in_picture_title); - - // select Picture-in-Picture - mDevice.findObject(new UiSelector().text(titlePictureInPictureApp)).click(); - - // Picture-in-picture settings page should launch and no crash - final UiObject actionBar = mDevice.findObject(new UiSelector().resourceId( - "com.android.settings:id/action_bar")); - final UiObject title = actionBar.getChild( - new UiSelector().className(TextView.class.getName())); - assertEquals(titlePictureInPictureApp, title.getText()); - } - - private void launchSpecialApps() throws Exception { - final Intent settingsIntent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setPackage(mTargetPackage) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getInstrumentation().getContext().startActivity(settingsIntent); - final String titleApps = mTargetContext.getResources().getString( - R.string.app_and_notification_dashboard_title); - mDevice.findObject(new UiSelector().text(titleApps)).click(); - final String titleAdvance = mTargetContext.getResources().getString( - R.string.advanced_section_header); - mDevice.findObject(new UiSelector().text(titleAdvance)).click(); - final String titleSpecialApps = mTargetContext.getResources().getString( - R.string.special_access); - - try { - // scollbar may or may not be present, depending on how many recents app are there. If - // the page is scrollable, scroll to the bottom to show the special app access settings. - final UiScrollable settings = new UiScrollable( - new UiSelector().packageName(mTargetContext.getPackageName()).scrollable(true)); - settings.scrollTextIntoView(titleSpecialApps); - } catch (UiObjectNotFoundException e) { - // ignore - } - - mDevice.findObject(new UiSelector().text(titleSpecialApps)).click(); - } - -} diff --git a/tests/unit/src/com/android/settings/backup/BackupIntentTest.java b/tests/unit/src/com/android/settings/backup/BackupIntentTest.java index 0115c569aef..54e7451d8a2 100644 --- a/tests/unit/src/com/android/settings/backup/BackupIntentTest.java +++ b/tests/unit/src/com/android/settings/backup/BackupIntentTest.java @@ -39,7 +39,7 @@ import java.util.List; public class BackupIntentTest { private static final String INTENT_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS"; private static final String BACKUP_SETTINGS_ACTIVITY = - "com.android.settings.backup.UserBackupSettingsActivity"; + "com.android.settings.Settings$PrivacyDashboardActivity"; private Context mContext; diff --git a/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java b/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java deleted file mode 100644 index aec6dd22df1..00000000000 --- a/tests/unit/src/com/android/settings/bluetooth/BluetoothDeviceDetailsRotationTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.bluetooth; - -import static org.mockito.Mockito.when; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.RemoteException; -import android.support.test.uiautomator.UiDevice; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.settings.SettingsActivity; -import com.android.settings.core.SubSettingLauncher; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.core.instrumentation.Instrumentable; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class BluetoothDeviceDetailsRotationTest { - private Context mContext; - private UiDevice mUiDevice; - private Instrumentation mInstrumentation; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private CachedBluetoothDevice mCachedDevice; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private LocalBluetoothManager mBluetoothManager; - - private String mDeviceAddress; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getTargetContext(); - mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - - mDeviceAddress = "AA:BB:CC:DD:EE:FF"; - when(mCachedDevice.getAddress()).thenReturn(mDeviceAddress); - when(mCachedDevice.getName()).thenReturn("Mock Device"); - - BluetoothDeviceDetailsFragment.sTestDataFactory = - new BluetoothDeviceDetailsFragment.TestDataFactory() { - @Override - public CachedBluetoothDevice getDevice(String deviceAddress) { - return mCachedDevice; - } - - @Override - public LocalBluetoothManager getManager(Context context) { - return mBluetoothManager; - } - }; - } - - @Test - public void rotation() { - Intent intent = new Intent("android.settings.BLUETOOTH_SETTINGS"); - SettingsActivity activity = (SettingsActivity) mInstrumentation.startActivitySync(intent); - Bundle args = new Bundle(1); - args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, mDeviceAddress); - new SubSettingLauncher(activity) - .setDestination(BluetoothDeviceDetailsFragment.class.getName()) - .setTitleText("test") - .setArguments(args) - .setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN) - .launch(); - try { - mUiDevice.setOrientationLeft(); - mUiDevice.setOrientationNatural(); - mUiDevice.setOrientationRight(); - mUiDevice.setOrientationNatural(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } -} \ No newline at end of file diff --git a/tests/unit/src/com/android/settings/bluetooth/DevicePickerActivityTest.java b/tests/unit/src/com/android/settings/bluetooth/DevicePickerActivityTest.java deleted file mode 100644 index e531e0a9740..00000000000 --- a/tests/unit/src/com/android/settings/bluetooth/DevicePickerActivityTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.bluetooth; - -import android.app.Instrumentation; -import android.content.Intent; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class DevicePickerActivityTest { - - private Instrumentation mInstrumentation; - - @Before - public void setUp() throws Exception { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - } - - @Test - public void startActivityNoCrash() { - mInstrumentation.startActivitySync( - new Intent("android.bluetooth.devicepicker.action.LAUNCH")); - // No crash - } -} diff --git a/tests/unit/src/com/android/settings/connecteddevice/ConnectedDeviceActivityTest.java b/tests/unit/src/com/android/settings/connecteddevice/ConnectedDeviceActivityTest.java deleted file mode 100644 index 2957c4cfdc6..00000000000 --- a/tests/unit/src/com/android/settings/connecteddevice/ConnectedDeviceActivityTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.connecteddevice; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.Instrumentation; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.text.TextUtils; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class ConnectedDeviceActivityTest { - private static final String INTENT_ACTION = "android.intent.action.MAIN"; - private static final String CONNECTED_DEVICE_TITLE = "Connected devices"; - - private Instrumentation mInstrumentation; - - @Before - public void setUp() throws Exception { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - } - - @Test - public void queryConnectedDeviceActivity_onlyOneResponse() { - final PackageManager packageManager = mInstrumentation.getContext().getPackageManager(); - final Intent intent = new Intent(INTENT_ACTION); - - int count = 0; - final List resolveInfoList = packageManager.queryIntentActivities(intent, - PackageManager.GET_META_DATA); - for (ResolveInfo info : resolveInfoList) { - if (TextUtils.equals(info.activityInfo.loadLabel(packageManager).toString(), - CONNECTED_DEVICE_TITLE)) { - count++; - } - } - - assertThat(count).isEqualTo(1); - } - -} diff --git a/tests/unit/src/com/android/settings/dashboard/PreferenceThemeTest.java b/tests/unit/src/com/android/settings/dashboard/PreferenceThemeTest.java index 18a5e70f32d..0ae5597f356 100644 --- a/tests/unit/src/com/android/settings/dashboard/PreferenceThemeTest.java +++ b/tests/unit/src/com/android/settings/dashboard/PreferenceThemeTest.java @@ -18,13 +18,9 @@ package com.android.settings.dashboard; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static com.android.settings.dashboard.FirstIdViewMatcher.withFirstId; - import static org.hamcrest.Matchers.allOf; import android.app.Instrumentation; @@ -57,12 +53,6 @@ public class PreferenceThemeTest { mTargetPackage = mTargetContext.getPackageName(); } - @Test - public void startPhoneStatus_preferenceIconSpaceReserved() throws InterruptedException { - launchPhoneStatus(); - onView(withFirstId(R.id.icon_frame)).check(matches(isDisplayed())); - } - @Test public void startSetupWizardLockScreen_preferenceIconSpaceNotReserved() { launchSetupWizardLockScreen(); @@ -72,14 +62,6 @@ public class PreferenceThemeTest { onView(withId(R.id.icon_container)).check(doesNotExist()); } - private void launchPhoneStatus() { - final Intent settingsIntent = new Intent("android.settings.DEVICE_INFO_SETTINGS") - .addCategory(Intent.CATEGORY_DEFAULT) - .setPackage(mTargetPackage) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - InstrumentationRegistry.getInstrumentation().startActivitySync(settingsIntent); - } - private void launchSetupWizardLockScreen() { final Intent settingsIntent = new Intent("com.android.settings.SETUP_LOCK_SCREEN") .addCategory(Intent.CATEGORY_DEFAULT) diff --git a/tests/unit/src/com/android/settings/datausage/MobileDataUsageActivityTest.java b/tests/unit/src/com/android/settings/datausage/MobileDataUsageActivityTest.java deleted file mode 100644 index 066d1997141..00000000000 --- a/tests/unit/src/com/android/settings/datausage/MobileDataUsageActivityTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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; - -import static junit.framework.Assert.assertEquals; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.NetworkTemplate; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class MobileDataUsageActivityTest { - private static final String TAG = "MobileDataUsageTest"; - @Test - public void test_mobileDataUsageIntent() { - final Context context = InstrumentationRegistry.getTargetContext(); - final PackageManager packageManager = context.getPackageManager(); - final int subId = SubscriptionManager.getDefaultSubscriptionId(); - final NetworkTemplate template = getNetworkTemplate(context, subId); - - Intent intent = new Intent(android.provider.Settings.ACTION_MOBILE_DATA_USAGE); - intent.putExtra(android.provider.Settings.EXTRA_NETWORK_TEMPLATE, template); - intent.putExtra(android.provider.Settings.EXTRA_SUB_ID, subId); - - assertEquals(packageManager.queryIntentActivities(intent, 0).size(), 1); - - context.startActivity(intent); - // Should exit gracefully without crashing. - } - - private NetworkTemplate getNetworkTemplate(Context context, int subId) { - TelephonyManager tm = (TelephonyManager) context - .getSystemService(Context.TELEPHONY_SERVICE); - NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - tm.getSubscriberId(subId)); - return NetworkTemplate.normalize(mobileAll, - tm.getMergedSubscriberIds()); - } -} diff --git a/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java b/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java index 26595292f3d..a04c08d37e7 100644 --- a/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java +++ b/tests/unit/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java @@ -56,9 +56,6 @@ public class TimeZoneDataTest { */ assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/Simferopol").isEmpty()) .isTrue(); - // Metlakatla has the same time as Anchorage after 2015 - assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Metlakatla").isEmpty()) - .isTrue(); assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/London").isEmpty()) .isFalse(); assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Los_Angeles").isEmpty()) diff --git a/tests/unit/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java b/tests/unit/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java deleted file mode 100644 index a0053be5a37..00000000000 --- a/tests/unit/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.android.settings.deviceinfo; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.intent.Intents.intended; -import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; - -import androidx.test.espresso.intent.rule.IntentsTestRule; -import androidx.test.filters.SmallTest; - -import com.android.settings.R; -import com.android.settings.Settings.StorageDashboardActivity; -import com.android.settings.deletionhelper.AutomaticStorageManagerSettings; - -import org.junit.Rule; -import org.junit.Test; - -@SmallTest -public class StorageDashboardFragmentTest { - - public static final String EXTRA_KEY = ":settings:show_fragment"; - - @Rule - public IntentsTestRule mActivityRule = - new IntentsTestRule<>(StorageDashboardActivity.class, true, true); - - @Test - public void testStorageManagePreference_canClickTextView() throws InterruptedException { - // Click on the actual textbox instead of just somewhere in the preference - onView(withText(R.string.automatic_storage_manager_preference_title)).perform(click()); - - // Check that it worked by seeing if we switched screens - intended(hasExtra(equalTo(EXTRA_KEY), - containsString(AutomaticStorageManagerSettings.class.getName()))); - - } -} diff --git a/tests/unit/src/com/android/settings/dream/DreamSettingsLaunchTest.java b/tests/unit/src/com/android/settings/dream/DreamSettingsLaunchTest.java deleted file mode 100644 index 6a2abd54552..00000000000 --- a/tests/unit/src/com/android/settings/dream/DreamSettingsLaunchTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.dream; - -import android.content.Context; -import android.content.Intent; -import android.provider.Settings; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class DreamSettingsLaunchTest { - - @Test - public void launchFromIntent_doesNotCrash() { - final Context context = InstrumentationRegistry.getTargetContext(); - Intent intent = new Intent(Settings.ACTION_DREAM_SETTINGS); - - context.startActivity(intent); - } -} diff --git a/tests/unit/src/com/android/settings/tests/DrawOverlayDetailsTest.java b/tests/unit/src/com/android/settings/tests/DrawOverlayDetailsTest.java deleted file mode 100644 index d450bf0cea3..00000000000 --- a/tests/unit/src/com/android/settings/tests/DrawOverlayDetailsTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016 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.tests; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.hamcrest.core.IsNot.not; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiScrollable; -import android.support.test.uiautomator.UiSelector; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.settings.R; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class DrawOverlayDetailsTest { - private final static String PACKAGE_SYSTEM_UI = "com.android.systemui"; - - @Test - public void testSystemUiDrawOverlayDetails_Disabled() throws Exception{ - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - instrumentation.startActivitySync(new Intent(android.provider.Settings - .ACTION_MANAGE_OVERLAY_PERMISSION)); - - final Context targetContext = instrumentation.getTargetContext(); - - final PackageManager packageManager = targetContext.getPackageManager(); - final String appName = (String) packageManager.getApplicationLabel(packageManager - .getApplicationInfo(PACKAGE_SYSTEM_UI, PackageManager.GET_META_DATA)); - - final UiDevice device = UiDevice.getInstance(instrumentation); - device.waitForIdle(); - - openActionBarOverflowOrOptionsMenu(targetContext); - onView(withText(targetContext.getString(R.string.menu_show_system))).perform(click()); - device.waitForIdle(); - - final UiScrollable settings = new UiScrollable( - new UiSelector().packageName(targetContext.getPackageName()).scrollable(true)); - settings.scrollTextIntoView(appName); - onView(withText(appName)).perform(click()); - onView(withText(targetContext.getString(R.string.permit_draw_overlay))).check(matches - (not(isEnabled()))); - } - -} diff --git a/tests/unit/src/com/android/settings/tests/KeepOnScreenTest.java b/tests/unit/src/com/android/settings/tests/KeepOnScreenTest.java deleted file mode 100644 index b930ffb1f67..00000000000 --- a/tests/unit/src/com/android/settings/tests/KeepOnScreenTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2016 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.tests; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static junit.framework.Assert.assertEquals; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.os.BatteryManager; -import android.provider.Settings; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.settings.R; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class KeepOnScreenTest { - private static int EXPECTED_FLAG = BatteryManager.BATTERY_PLUGGED_AC - | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS; - - @Test - public void testStayAwake_turnOn_StayAwakeWhileWirelessCharging() throws Exception{ - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - instrumentation.startActivitySync(new Intent(android.provider.Settings - .ACTION_APPLICATION_DEVELOPMENT_SETTINGS)); - - final Context targetContext = instrumentation.getTargetContext(); - final int prevFlag = Settings.Global.getInt(targetContext.getContentResolver(), Settings - .Global.STAY_ON_WHILE_PLUGGED_IN); - - // Turn on "Stay Awake" if needed - if (prevFlag == 0) { - onView(withText(R.string.keep_screen_on)).perform(click()); - } - - final int currentFlag = Settings.Global.getInt(targetContext.getContentResolver(), Settings - .Global.STAY_ON_WHILE_PLUGGED_IN); - - assertEquals(EXPECTED_FLAG, currentFlag); - - // Since this app doesn't have permission(and shouldn't have) to change global setting, we - // can only tearDown in this way - if (prevFlag != currentFlag) { - onView(withText(R.string.keep_screen_on)).perform(click()); - } - } -} diff --git a/tests/unit/src/com/android/settings/tests/PrivateVolumeSettingsTest.java b/tests/unit/src/com/android/settings/tests/PrivateVolumeSettingsTest.java deleted file mode 100644 index 2760a0782a4..00000000000 --- a/tests/unit/src/com/android/settings/tests/PrivateVolumeSettingsTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 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.tests; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.Instrumentation; -import android.content.Intent; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class PrivateVolumeSettingsTest { - @Test - public void test_ManageStorageNotShown() { - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - instrumentation.startActivitySync( - new Intent(android.provider.Settings.ACTION_INTERNAL_STORAGE_SETTINGS)); - onView(withText(com.android.settings.R.string.storage_menu_manage)).check(doesNotExist()); - } -} \ No newline at end of file diff --git a/tests/unit/src/com/android/settings/tests/SettingsRestoreAfterCloseTest.java b/tests/unit/src/com/android/settings/tests/SettingsRestoreAfterCloseTest.java deleted file mode 100644 index 3c6caf78644..00000000000 --- a/tests/unit/src/com/android/settings/tests/SettingsRestoreAfterCloseTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2016 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.tests; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.Intent; -import android.provider.Settings; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.Until; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class SettingsRestoreAfterCloseTest { - private static final String PACKAGE_SETTINGS = "com.android.settings"; - private static final int TIME_OUT = 2000; - - private boolean mAlwaysFinish; - - @Before - public void setUp() throws Exception { - // To make sure when we press home button, the activity will be destroyed by OS - Context context = InstrumentationRegistry.getContext(); - mAlwaysFinish = Settings.Global.getInt( - context.getContentResolver(), Settings.Global - .ALWAYS_FINISH_ACTIVITIES, 0) - != 0; - - ActivityManager.getService().setAlwaysFinish(true); - } - - @After - public void tearDown() throws Exception { - ActivityManager.getService().setAlwaysFinish(mAlwaysFinish); - } - - @Test - public void testRtlStability_AppCloseAndReOpen_shouldNotCrash() throws Exception { - - final UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation - ()); - uiDevice.pressHome(); - - // Open the settings app - startSettingsMainActivity(uiDevice); - - // Press home button - uiDevice.pressHome(); - final String launcherPackage = uiDevice.getLauncherPackageName(); - uiDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIME_OUT); - - // Open the settings again - startSettingsMainActivity(uiDevice); - } - - private void startSettingsMainActivity(UiDevice uiDevice) { - Context context = InstrumentationRegistry.getContext(); - context.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS)); - uiDevice.wait(Until.hasObject(By.pkg(PACKAGE_SETTINGS).depth(0)), TIME_OUT); - } -} diff --git a/tests/unit/src/com/android/settings/users/UserSettingsTest.java b/tests/unit/src/com/android/settings/users/UserSettingsTest.java deleted file mode 100644 index 93f62f39a15..00000000000 --- a/tests/unit/src/com/android/settings/users/UserSettingsTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2016 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.users; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.content.Intent; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiScrollable; -import android.support.test.uiautomator.UiSelector; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class UserSettingsTest { - - private static final String SYSTEM = "System"; - private static final String ADVANCED = "Advanced"; - private static final String USERS = "Multiple users"; - private static final String EMERGNENCY_INFO = "Emergency information"; - private static final String ADD_USERS_WHEN_LOCKED = "Add users"; - private static final String SWITCH_USER_BUTTON = "com.android.systemui:id/multi_user_switch"; - private static final String SETTINGS_BUTTON = "com.android.systemui:id/settings_button"; - private static final String PRIMARY_USER = "Owner"; - private static final String GUEST_USER = "Guest"; - private static final String ADD_GUEST = "Add guest"; - private static final String CONTINUE = "Yes, continue"; - - private UiDevice mDevice; - private Context mContext; - private String mTargetPackage; - - @Before - public void setUp() { - mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - mContext = InstrumentationRegistry.getTargetContext(); - mTargetPackage = mContext.getPackageName(); - } - - @Test - public void testEmergencyInfoNotExists() throws Exception { - launchUserSettings(); - UiObject emergencyInfoPreference = - mDevice.findObject(new UiSelector().text(EMERGNENCY_INFO)); - - assertThat(emergencyInfoPreference.exists()).isFalse(); - } - - @Test - public void testAddUsersWhenLockedNotExists() throws Exception { - launchUserSettings(); - UiObject addUsersPreference = - mDevice.findObject(new UiSelector().text(ADD_USERS_WHEN_LOCKED)); - assertThat(addUsersPreference.exists()).isFalse(); - } - - @Test - public void testUsersExistsOnSecondaryUser() throws Exception { - // switch to guest user - switchToOrCreateGuest(); - // launch settings (launch from intent doesn't work, hence launch from quick settings) - mDevice.openQuickSettings(); - mDevice.findObject(new UiSelector().resourceId(SETTINGS_BUTTON)).click(); - // launch system settings and expand whole screen - final UiScrollable settings = new UiScrollable( - new UiSelector().packageName(mTargetPackage).scrollable(true)); - final String titleSystem = SYSTEM; - settings.scrollTextIntoView(titleSystem); - mDevice.findObject(new UiSelector().text(titleSystem)).click(); - mDevice.findObject(new UiSelector().text(ADVANCED)).click(); - - final boolean hasUsersSettings = mDevice.findObject(new UiSelector().text(USERS)).exists(); - - // switch back to primary user - mDevice.openQuickSettings(); - mDevice.findObject(new UiSelector().resourceId(SWITCH_USER_BUTTON)).click(); - mDevice.findObject(new UiSelector().text(PRIMARY_USER)).click(); - - assertThat(hasUsersSettings).isTrue(); - } - - private void launchSettings() { - Intent settingsIntent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setPackage(mTargetPackage) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(settingsIntent); - } - - private void launchUserSettings() throws Exception { - launchSettings(); - final UiScrollable settings = new UiScrollable( - new UiSelector().packageName(mTargetPackage).scrollable(true)); - final String titleSystem = SYSTEM; - settings.scrollTextIntoView(titleSystem); - mDevice.findObject(new UiSelector().text(titleSystem)).click(); - mDevice.findObject(new UiSelector().text(ADVANCED)).click(); - mDevice.findObject(new UiSelector().text(USERS)).click(); - } - - private void switchToOrCreateGuest() throws UiObjectNotFoundException { - mDevice.openQuickSettings(); - mDevice.findObject(new UiSelector().resourceId(SWITCH_USER_BUTTON)).click(); - // if no existing guest user, select "Add guest", otherwise select "Guest" - final UiObject addGuest = mDevice.findObject(new UiSelector().text(ADD_GUEST)); - if (addGuest.exists()) { - addGuest.click(); - mDevice.waitForIdle(); - mDevice.pressBack(); - } else { - mDevice.findObject(new UiSelector().text(GUEST_USER)).click(); - mDevice.waitForIdle(); - mDevice.findObject(new UiSelector().text(CONTINUE)).click(); - mDevice.waitForIdle(); - } - } -} diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java index cb586e43432..2de66110c55 100644 --- a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java +++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java @@ -56,7 +56,8 @@ public class WifiTetherSettingsTest { mTetherActivityIntent = new Intent() .setClassName(mInstrumentation.getTargetContext().getPackageName(), Settings.TetherSettingsActivity.class.getName()) - .setPackage(mInstrumentation.getTargetContext().getPackageName()); + .setPackage(mInstrumentation.getTargetContext().getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } @After @@ -69,7 +70,6 @@ public class WifiTetherSettingsTest { launchWifiTetherActivity(); onView(withText("Hotspot name")).check(matches(isDisplayed())); onView(withText("Hotspot password")).check(matches(isDisplayed())); - onView(withText("AP Band")).check(matches(isDisplayed())); } private void launchWifiTetherActivity() { From e0a722e13058b95526764abc522ad5590003cca6 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 25 Feb 2019 12:46:34 -0800 Subject: [PATCH 07/17] Merge Copyable into Sliceable. It's only a slice concept. Regular preference copyability is handled in xml. Bug: 112427717 Test: rebuild Change-Id: Iaba7077c320cd03a5963797916a60e0dc80fdbbe --- .../BuildNumberPreferenceController.java | 8 ++- .../PhoneNumberPreferenceController.java | 9 ++-- ...wareVersionDetailPreferenceController.java | 7 ++- .../imei/ImeiInfoPreferenceController.java | 11 ++-- src/com/android/settings/slices/Copyable.java | 51 ------------------- .../slices/SliceBroadcastReceiver.java | 4 +- .../settings/slices/SliceBuilderUtils.java | 2 +- .../android/settings/slices/Sliceable.java | 36 +++++++++++++ .../testutils/FakeCopyableController.java | 6 +-- 9 files changed, 65 insertions(+), 69 deletions(-) delete mode 100644 src/com/android/settings/slices/Copyable.java diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java index ec0ab36d270..f13af9466cd 100644 --- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java @@ -42,7 +42,6 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; -import com.android.settings.slices.Copyable; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -50,7 +49,7 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.development.DevelopmentSettingsEnabler; -public class BuildNumberPreferenceController extends BasePreferenceController implements Copyable, +public class BuildNumberPreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart { static final int TAPS_TO_BE_A_DEVELOPER = 7; @@ -108,6 +107,11 @@ public class BuildNumberPreferenceController extends BasePreferenceController im return true; } + @Override + public boolean isCopyableSlice() { + return true; + } + @Override public void copy() { final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService( diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java index 598dfb1542f..3767860add0 100644 --- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java @@ -35,14 +35,12 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.slices.Copyable; import com.android.settingslib.DeviceInfoUtils; import java.util.ArrayList; import java.util.List; -public class PhoneNumberPreferenceController extends BasePreferenceController implements - Copyable { +public class PhoneNumberPreferenceController extends BasePreferenceController { private final static String KEY_PHONE_NUMBER = "phone_number"; @@ -98,6 +96,11 @@ public class PhoneNumberPreferenceController extends BasePreferenceController im return true; } + @Override + public boolean isCopyableSlice() { + return true; + } + @Override public void copy() { final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService( diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java index 7a19fdef28e..9f3d6e5ed3b 100644 --- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java +++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java @@ -31,12 +31,11 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.slices.Copyable; +import com.android.settings.slices.Sliceable; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; -public class FirmwareVersionDetailPreferenceController extends BasePreferenceController implements - Copyable { +public class FirmwareVersionDetailPreferenceController extends BasePreferenceController { private static final String TAG = "firmwareDialogCtrl"; private static final int DELAY_TIMER_MILLIS = 500; @@ -119,7 +118,7 @@ public class FirmwareVersionDetailPreferenceController extends BasePreferenceCon @Override public void copy() { - Copyable.setCopyContent(mContext, getSummary(), + Sliceable.setCopyContent(mContext, getSummary(), mContext.getText(R.string.firmware_version)); } } diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java index 96ff83c6f84..77d975ed1eb 100644 --- a/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java +++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java @@ -29,7 +29,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.slices.Copyable; +import com.android.settings.slices.Sliceable; import com.android.settingslib.Utils; import java.util.ArrayList; @@ -38,7 +38,7 @@ import java.util.List; /** * Controller that manages preference for single and multi sim devices. */ -public class ImeiInfoPreferenceController extends BasePreferenceController implements Copyable { +public class ImeiInfoPreferenceController extends BasePreferenceController { private final boolean mIsMultiSim; private final TelephonyManager mTelephonyManager; @@ -105,9 +105,14 @@ public class ImeiInfoPreferenceController extends BasePreferenceController imple return true; } + @Override + public boolean isCopyableSlice() { + return true; + } + @Override public void copy() { - Copyable.setCopyContent(mContext, getSummary(), mContext.getText(R.string.status_imei)); + Sliceable.setCopyContent(mContext, getSummary(), mContext.getText(R.string.status_imei)); } private void updatePreference(Preference preference, int simSlot) { diff --git a/src/com/android/settings/slices/Copyable.java b/src/com/android/settings/slices/Copyable.java deleted file mode 100644 index a480063a71c..00000000000 --- a/src/com/android/settings/slices/Copyable.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2018 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.slices; - -import static android.content.Context.CLIPBOARD_SERVICE; - -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.widget.Toast; - -import com.android.settings.R; - -/** - * Provide the copy ability for preference controller to copy the data to the clipboard. - */ -public interface Copyable { - /** - * Copy the key slice information to the clipboard. - * It is highly recommended to show the toast to notify users when implemented this function. - */ - void copy(); - - /** - * Set the copy content to the clipboard and show the toast. - */ - static void setCopyContent(Context context, CharSequence copyContent, - CharSequence messageTitle) { - final ClipboardManager clipboard = (ClipboardManager) context.getSystemService( - CLIPBOARD_SERVICE); - final ClipData clip = ClipData.newPlainText("text", copyContent); - clipboard.setPrimaryClip(clip); - - final String toast = context.getString(R.string.copyable_slice_toast, messageTitle); - Toast.makeText(context, toast, Toast.LENGTH_SHORT).show(); - } -} diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index 061cf1893f7..2a9b491713c 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -184,7 +184,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { final BasePreferenceController controller = getPreferenceController(context, key); - if (!(controller instanceof Copyable)) { + if (!(controller instanceof Sliceable)) { throw new IllegalArgumentException( "Copyable action passed for a non-copyable key:" + key); } @@ -197,7 +197,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { return; } - ((Copyable) controller).copy(); + ((Sliceable) controller).copy(); } /** diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index 8f8543131ab..c3869a6d5d6 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -93,7 +93,7 @@ public class SliceBuilderUtils { return buildUnavailableSlice(context, sliceData); } - if (controller instanceof Copyable) { + if (controller.isCopyableSlice()) { return buildCopyableSlice(context, sliceData, controller); } diff --git a/src/com/android/settings/slices/Sliceable.java b/src/com/android/settings/slices/Sliceable.java index ddec2e1a973..b00ab8207eb 100644 --- a/src/com/android/settings/slices/Sliceable.java +++ b/src/com/android/settings/slices/Sliceable.java @@ -16,7 +16,15 @@ package com.android.settings.slices; +import static android.content.Context.CLIPBOARD_SERVICE; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.IntentFilter; +import android.widget.Toast; + +import com.android.settings.R; /** * A collection of API making a PreferenceController "sliceable" @@ -55,4 +63,32 @@ public interface Sliceable { default boolean hasAsyncUpdate() { return false; } + + /** + * Copy the key slice information to the clipboard. + * It is highly recommended to show the toast to notify users when implemented this function. + */ + default void copy() { + } + + /** + * Whether or not it's a copyable slice. + */ + default boolean isCopyableSlice() { + return false; + } + + /** + * Set the copy content to the clipboard and show the toast. + */ + static void setCopyContent(Context context, CharSequence copyContent, + CharSequence messageTitle) { + final ClipboardManager clipboard = (ClipboardManager) context.getSystemService( + CLIPBOARD_SERVICE); + final ClipData clip = ClipData.newPlainText("text", copyContent); + clipboard.setPrimaryClip(clip); + + final String toast = context.getString(R.string.copyable_slice_toast, messageTitle); + Toast.makeText(context, toast, Toast.LENGTH_SHORT).show(); + } } diff --git a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java index 31e955c8cdf..e51a2492844 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java @@ -19,9 +19,8 @@ package com.android.settings.testutils; import android.content.Context; import com.android.settings.core.BasePreferenceController; -import com.android.settings.slices.Copyable; -public class FakeCopyableController extends BasePreferenceController implements Copyable { +public class FakeCopyableController extends BasePreferenceController { public FakeCopyableController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -38,6 +37,7 @@ public class FakeCopyableController extends BasePreferenceController implements } @Override - public void copy() { + public boolean isCopyableSlice() { + return true; } } From 8ae1514299c7fa8e93cb43bed086acad2c94e25b Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 25 Feb 2019 13:36:38 -0800 Subject: [PATCH 08/17] Make model & hardware UI full screen. Bug: 112427717 Test: robotests Change-Id: I9f1edb0ab377aff142b57d86f4fa218b755356b1 --- res/layout/dialog_hardware_info.xml | 65 ------------- res/xml/hardware_info.xml | 52 +++++++++++ res/xml/my_device_info.xml | 3 +- .../HardwareInfoDialogFragment.java | 91 ------------------- ... => HardwareInfoPreferenceController.java} | 31 +------ .../aboutphone/MyDeviceInfoFragment.java | 3 - .../DeviceModelPreferenceController.java | 42 +++++++++ .../hardwareinfo/HardwareInfoFragment.java | 71 +++++++++++++++ .../HardwareRevisionPreferenceController.java | 46 ++++++++++ .../SerialNumberPreferenceController.java | 46 ++++++++++ .../deviceinfo/DeviceInfoSlice.java | 4 +- .../HardwareInfoDialogFragmentTest.java | 66 -------------- .../DeviceModelPreferenceControllerTest.java | 64 +++++++++++++ ...HardwareInfoPreferenceControllerTest.java} | 42 ++------- 14 files changed, 335 insertions(+), 291 deletions(-) delete mode 100644 res/layout/dialog_hardware_info.xml create mode 100644 res/xml/hardware_info.xml delete mode 100644 src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java rename src/com/android/settings/deviceinfo/{DeviceModelPreferenceController.java => HardwareInfoPreferenceController.java} (71%) create mode 100644 src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java create mode 100644 src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/deviceinfo/HardwareInfoDialogFragmentTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceControllerTest.java rename tests/robotests/src/com/android/settings/deviceinfo/{DeviceModelPreferenceControllerTest.java => hardwareinfo/HardwareInfoPreferenceControllerTest.java} (64%) diff --git a/res/layout/dialog_hardware_info.xml b/res/layout/dialog_hardware_info.xml deleted file mode 100644 index 7ea47831556..00000000000 --- a/res/layout/dialog_hardware_info.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/xml/hardware_info.xml b/res/xml/hardware_info.xml new file mode 100644 index 00000000000..2e35101aca6 --- /dev/null +++ b/res/xml/hardware_info.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml index 918e8ec0cf3..83bf5c45d08 100644 --- a/res/xml/my_device_info.xml +++ b/res/xml/my_device_info.xml @@ -105,7 +105,8 @@ settings:keywords="@string/keywords_model_and_hardware" android:summary="@string/summary_placeholder" settings:allowDynamicSummaryInSlice="true" - settings:controller="com.android.settings.deviceinfo.DeviceModelPreferenceController"/> + android:fragment="com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFragment" + settings:controller="com.android.settings.deviceinfo.HardwareInfoPreferenceController"/> msvSuffixTask = new FutureTask<>(() -> DeviceInfoUtils.getMsvSuffix()); diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java index c20e857a803..e6afb7b821c 100644 --- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java +++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java @@ -31,7 +31,6 @@ import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.deviceinfo.BluetoothAddressPreferenceController; import com.android.settings.deviceinfo.BuildNumberPreferenceController; -import com.android.settings.deviceinfo.DeviceModelPreferenceController; import com.android.settings.deviceinfo.DeviceNamePreferenceController; import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController; import com.android.settings.deviceinfo.FeedbackPreferenceController; @@ -41,7 +40,6 @@ import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController; import com.android.settings.deviceinfo.SafetyInfoPreferenceController; import com.android.settings.deviceinfo.UptimePreferenceController; import com.android.settings.deviceinfo.WifiMacAddressPreferenceController; -import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceController; import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController; import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceController; import com.android.settings.search.BaseSearchIndexProvider; @@ -77,7 +75,6 @@ public class MyDeviceInfoFragment extends DashboardFragment @Override public void onAttach(Context context) { super.onAttach(context); - use(DeviceModelPreferenceController.class).setHost(this /* parent */); use(ImeiInfoPreferenceController.class).setHost(this /* parent */); use(DeviceNamePreferenceController.class).setHost(this /* parent */); mBuildNumberPreferenceController = use(BuildNumberPreferenceController.class); diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceController.java new file mode 100644 index 00000000000..42c7b0104e7 --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceController.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + +import android.content.Context; + +import com.android.settings.deviceinfo.HardwareInfoPreferenceController; + +public class DeviceModelPreferenceController extends HardwareInfoPreferenceController { + + public DeviceModelPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + final int availability = super.getAvailabilityStatus(); + if (availability == AVAILABLE_UNSEARCHABLE) { + return AVAILABLE; + } + return availability; + } + + @Override + public boolean isSliceable() { + return true; + } +} diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java new file mode 100644 index 00000000000..40e73efe882 --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFragment.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + + +@SearchIndexable +public class HardwareInfoFragment extends DashboardFragment { + + public static final String TAG = "HardwareInfo"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.DIALOG_SETTINGS_HARDWARE_INFO; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.hardware_info; + } + + @Override + protected String getLogTag() { + return TAG; + } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.hardware_info; + result.add(sir); + return result; + } + + @Override + protected boolean isPageSearchEnabled(Context context) { + return context.getResources().getBoolean(R.bool.config_show_device_model); + } + }; +} diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java new file mode 100644 index 00000000000..ec0cdb2a362 --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + +import android.content.Context; +import android.os.SystemProperties; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; + +public class HardwareRevisionPreferenceController extends BasePreferenceController { + + public HardwareRevisionPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_device_model) + ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean isSliceable() { + return true; + } + + @Override + public CharSequence getSummary() { + return SystemProperties.get("ro.boot.hardware.revision"); + } +} diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java new file mode 100644 index 00000000000..4485c53d7ae --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + +import android.content.Context; +import android.os.Build; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; + +public class SerialNumberPreferenceController extends BasePreferenceController { + + public SerialNumberPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_device_model) + ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean isSliceable() { + return true; + } + + @Override + public CharSequence getSummary() { + return Build.getSerial(); + } +} diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java index e278baae130..48a9aa54617 100644 --- a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java +++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java @@ -36,7 +36,7 @@ import androidx.slice.builders.SliceAction; import com.android.settings.R; import com.android.settings.SubSettings; import com.android.settings.Utils; -import com.android.settings.deviceinfo.DeviceModelPreferenceController; +import com.android.settings.deviceinfo.HardwareInfoPreferenceController; import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; @@ -107,7 +107,7 @@ public class DeviceInfoSlice implements CustomSliceable { } private CharSequence getDeviceModel() { - return DeviceModelPreferenceController.getDeviceModel(); + return HardwareInfoPreferenceController.getDeviceModel(); } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/deviceinfo/HardwareInfoDialogFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/HardwareInfoDialogFragmentTest.java deleted file mode 100644 index 29d9a7c8aa2..00000000000 --- a/tests/robotests/src/com/android/settings/deviceinfo/HardwareInfoDialogFragmentTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.deviceinfo; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.os.SystemProperties; -import android.view.View; - -import androidx.fragment.app.FragmentActivity; - -import com.android.settings.R; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class HardwareInfoDialogFragmentTest { - - private FragmentActivity mActivity; - - @Before - public void setUp() { - mActivity = Robolectric.setupActivity(FragmentActivity.class); - } - - @Test - public void display_shouldShowHardwareRevision() { - final String TEST_HARDWARE_REV = "123"; - SystemProperties.set("ro.boot.hardware.revision", TEST_HARDWARE_REV); - - final HardwareInfoDialogFragment fragment = spy(HardwareInfoDialogFragment.newInstance()); - doReturn("").when(fragment).getSerialNumber(); - fragment.show(mActivity.getSupportFragmentManager(), HardwareInfoDialogFragment.TAG); - - verify(fragment).setText( - any(View.class), eq(R.id.model_label), eq(R.id.model_value), - anyString()); - - verify(fragment).setText( - any(View.class), eq(R.id.hardware_rev_label), eq(R.id.hardware_rev_value), - anyString()); - } -} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceControllerTest.java new file mode 100644 index 00000000000..1204c443e1d --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/DeviceModelPreferenceControllerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +public class DeviceModelPreferenceControllerTest { + + private Context mContext; + private DeviceModelPreferenceController mController; + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new DeviceModelPreferenceController(mContext, "test_key"); + } + + @Test + public void getAvailabilityStatus_configAllowed_available() { + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); + } + + @Test + @Config(qualifiers = "mcc999") + public void getAvailabilityStatus_configDisallowed_unavailable() { + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } + + @Test + public void isAlwaysSliceable() { + assertThat(mController.isSliceable()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoPreferenceControllerTest.java similarity index 64% rename from tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoPreferenceControllerTest.java index 6418cf8bb6f..413c4921bbd 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoPreferenceControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,56 +13,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.settings.deviceinfo; +package com.android.settings.deviceinfo.hardwareinfo; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import android.content.Context; import android.os.Build; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.deviceinfo.HardwareInfoPreferenceController; 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.annotation.Config; @RunWith(RobolectricTestRunner.class) -public class DeviceModelPreferenceControllerTest { +public class HardwareInfoPreferenceControllerTest { private final String KEY = "device_model"; - @Mock - private Fragment mFragment; private Preference mPreference; private PreferenceScreen mPreferenceScreen; private Context mContext; - private DeviceModelPreferenceController mController; + private HardwareInfoPreferenceController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mController = new DeviceModelPreferenceController(mContext, KEY); - mController.setHost(mFragment); + mController = new HardwareInfoPreferenceController(mContext, KEY); mPreference = new Preference(mContext); mPreference.setKey(KEY); final PreferenceManager preferenceManager = new PreferenceManager(mContext); @@ -73,7 +61,7 @@ public class DeviceModelPreferenceControllerTest { @Test public void isAvailable_returnTrueIfVisible() { assertThat(mController.getAvailabilityStatus()).isEqualTo( - BasePreferenceController.AVAILABLE); + BasePreferenceController.AVAILABLE_UNSEARCHABLE); } @Test @@ -90,22 +78,6 @@ public class DeviceModelPreferenceControllerTest { assertThat(containBuildModel(mPreference.getSummary())).isTrue(); } - @Test - public void clickPreference_shouldLaunchHardwareInfoDialog() { - FragmentManager fragmentManager = mock(FragmentManager.class); - when(mFragment.getFragmentManager()).thenReturn(fragmentManager); - when(fragmentManager.beginTransaction()).thenReturn(mock(FragmentTransaction.class)); - - assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue(); - verify(fragmentManager.beginTransaction()) - .add(any(HardwareInfoDialogFragment.class), eq(HardwareInfoDialogFragment.TAG)); - } - - @Test - public void isSliceable_shouldBeTrue() { - assertThat(mController.isSliceable()).isTrue(); - } - private boolean containBuildModel(CharSequence result) { final String oracle = mContext.getResources().getString(R.string.model_summary, Build.MODEL); From ac74050a7ccbfb0a924ebf06f9dc2ef0109fdd3d Mon Sep 17 00:00:00 2001 From: tmfang Date: Sun, 24 Feb 2019 23:21:58 +0800 Subject: [PATCH 09/17] Improve launch time for Apps & notifications page In original design, we reload usage data at least thrice for showing recent apps. For now, we only reload usage data once in constuctor. And we reload data again when we are calling updateState. Test: Open App & notifications page, and then I compare the lauch time with P platform device. Fixes: 126013076 Change-Id: Ida769f28a4419125e1948e36658686ee55bf51a5 --- .../RecentAppsPreferenceController.java | 35 ++++++++++------ .../RecentAppsPreferenceControllerTest.java | 41 ++++++++++++++++--- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java index fe52a8b92f5..838d75849ac 100644 --- a/src/com/android/settings/applications/RecentAppsPreferenceController.java +++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java @@ -82,6 +82,8 @@ public class RecentAppsPreferenceController extends BasePreferenceController Preference mAllAppPref; @VisibleForTesting Preference mDivider; + @VisibleForTesting + boolean mIsFirstLaunch; private final PackageManager mPm; private final UsageStatsManager mUsageStatsManager; @@ -93,6 +95,7 @@ public class RecentAppsPreferenceController extends BasePreferenceController private Fragment mHost; private Calendar mCal; private List mStats; + private List mRecentApps; private boolean mHasRecentApps; static { @@ -115,6 +118,9 @@ public class RecentAppsPreferenceController extends BasePreferenceController mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); mPowerManager = mContext.getSystemService(PowerManager.class); mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class); + mRecentApps = new ArrayList<>(); + mIsFirstLaunch = true; + reloadData(); } public void setFragment(Fragment fragment) { @@ -123,8 +129,7 @@ public class RecentAppsPreferenceController extends BasePreferenceController @Override public int getAvailabilityStatus() { - reloadData(); - return getDisplayableRecentAppList().isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE; + return mRecentApps.isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE; } @Override @@ -152,7 +157,11 @@ public class RecentAppsPreferenceController extends BasePreferenceController @Override public void updateState(Preference preference) { super.updateState(preference); - refreshUi(); + // In order to improve launch time, we don't load data again at first launch. + if (!mIsFirstLaunch) { + reloadData(); + refreshUi(); + } // Show total number of installed apps as See all's summary. new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, mContext.getPackageManager()) { @@ -167,6 +176,7 @@ public class RecentAppsPreferenceController extends BasePreferenceController } } }.execute(); + mIsFirstLaunch = false; } @Override @@ -177,11 +187,9 @@ public class RecentAppsPreferenceController extends BasePreferenceController @VisibleForTesting void refreshUi() { - reloadData(); - final List recentApps = getDisplayableRecentAppList(); - if (recentApps != null && !recentApps.isEmpty()) { + if (mRecentApps != null && !mRecentApps.isEmpty()) { mHasRecentApps = true; - displayRecentApps(recentApps); + displayRecentApps(); } else { mHasRecentApps = false; displayOnlyAppInfo(); @@ -197,6 +205,8 @@ public class RecentAppsPreferenceController extends BasePreferenceController : mUsageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_BEST, mCal.getTimeInMillis(), System.currentTimeMillis()); + + updateDisplayableRecentAppList(); } private void displayOnlyAppInfo() { @@ -206,10 +216,10 @@ public class RecentAppsPreferenceController extends BasePreferenceController mRecentAppsPreference.setVisible(false); } - private void displayRecentApps(List recentApps) { + private void displayRecentApps() { int showAppsCount = 0; - for (UsageStats stat : recentApps) { + for (UsageStats stat : mRecentApps) { final AppEntityInfo appEntityInfoInfo = createAppEntity(stat); if (appEntityInfoInfo != null) { mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo); @@ -246,8 +256,8 @@ public class RecentAppsPreferenceController extends BasePreferenceController .build(); } - private List getDisplayableRecentAppList() { - final List recentApps = new ArrayList<>(); + private void updateDisplayableRecentAppList() { + mRecentApps.clear(); final Map map = new ArrayMap<>(); final int statCount = mStats.size(); for (int i = 0; i < statCount; i++) { @@ -273,13 +283,12 @@ public class RecentAppsPreferenceController extends BasePreferenceController if (appEntry == null) { continue; } - recentApps.add(stat); + mRecentApps.add(stat); count++; if (count >= AppEntitiesHeaderController.MAXIMUM_APPS) { break; } } - return recentApps; } diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java index 1411bc0a30f..e2a16579ad4 100644 --- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java @@ -25,9 +25,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -146,6 +146,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; + mController.reloadData(); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -157,13 +158,17 @@ public class RecentAppsPreferenceControllerTest { } @Test - public void displayPreferenceAndUpdateState_shouldRefreshUi() { - doNothing().when(mController).refreshUi(); - + public void displayPreference_shouldNotReloadData() { mController.displayPreference(mScreen); - mController.updateState(mScreen); - verify(mController, times(2)).refreshUi(); + verify(mController, never()).reloadData(); + } + + @Test + public void displayPreference_shouldRefreshUi() { + mController.displayPreference(mScreen); + + verify(mController).refreshUi(); } @Test @@ -173,6 +178,25 @@ public class RecentAppsPreferenceControllerTest { assertThat(mController.mAppEntitiesController).isNotNull(); } + @Test + public void updateState_firstLaunch_shouldNotReloadData() { + mController.mIsFirstLaunch = true; + + mController.updateState(mRecentAppsPreference); + + verify(mController, never()).reloadData(); + } + + @Test + public void updateState_afterFirstLaunch_shouldReloadDataAndRefreshUi() { + mController.mIsFirstLaunch = false; + + mController.updateState(mRecentAppsPreference); + + verify(mController).reloadData(); + verify(mController).refreshUi(); + } + @Test public void updateState_threeValidRecentOpenAppsSet_setAppEntityThreeTime() { final List stats = new ArrayList<>(); @@ -203,6 +227,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; + mController.mIsFirstLaunch = false; mController.updateState(mRecentAppsPreference); @@ -243,6 +268,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; + mController.mIsFirstLaunch = false; mController.updateState(mRecentAppsPreference); @@ -274,6 +300,7 @@ public class RecentAppsPreferenceControllerTest { when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); mAppEntry.info = mApplicationInfo; + mController.mIsFirstLaunch = false; mController.updateState(mRecentAppsPreference); @@ -314,6 +341,7 @@ public class RecentAppsPreferenceControllerTest { // Make sure stat2 is considered an instant app. ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", (InstantAppDataProvider) (ApplicationInfo info) -> info == stat2Entry.info); + mController.mIsFirstLaunch = false; mController.updateState(mRecentAppsPreference); @@ -389,6 +417,7 @@ public class RecentAppsPreferenceControllerTest { .thenReturn(new ResolveInfo()); when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) .thenReturn(stats); + mController.mIsFirstLaunch = false; mController.updateState(mRecentAppsPreference); From 57a3c8bff7ee19c83f01447b1759216183b513cf Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Mon, 25 Feb 2019 20:21:46 +0800 Subject: [PATCH 10/17] Handle the IllegalStateException Handle the attempt to re-open an already-closed object: SQLiteDatabase problem Bug: 124451874 Test: robotest Change-Id: I750b2ce98cc2551c80c3bb4f25928e0e5a615cd9 --- src/com/android/settings/slices/SlicesIndexer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java index ec2be2922de..1b3a25ef876 100644 --- a/src/com/android/settings/slices/SlicesIndexer.java +++ b/src/com/android/settings/slices/SlicesIndexer.java @@ -71,7 +71,7 @@ class SlicesIndexer implements Runnable { long startTime = System.currentTimeMillis(); database.beginTransaction(); try { - mHelper.reconstruct(mHelper.getWritableDatabase()); + mHelper.reconstruct(database); List indexData = getSliceData(); insertSliceData(database, indexData); From e0f77323b5ebda237c63aae3de6d117f86012a43 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Tue, 26 Feb 2019 18:10:46 +0800 Subject: [PATCH 11/17] Update char limit for "Erase all data?" Increasing the character limit for the "Erase all data?" to 33 chars. Bug: 122929703 Test: rebuild Change-Id: I673c22878c1f1cfa2b2dd8f456689be31fb5ff77 --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 3ccc37d06cf..00b853cc377 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3625,7 +3625,7 @@ Erase everything No reset was performed because the System Clear service isn\u2019t available. - + Erase all data? Factory reset is not available for this user From 55889211901bf98cff4941e034e5f559cbb9f3b2 Mon Sep 17 00:00:00 2001 From: Beverly Date: Tue, 26 Feb 2019 10:38:53 -0500 Subject: [PATCH 12/17] Update settings notification ui tests Test: atest AppNotificationSettingsTest Test: atest ZenModeSettingsIntegrationTest Test: atest ChannelNotificationSettingsTest Fixes: 126253682 Change-Id: Ie7fc5f177eb418162ecf24b0c4818ee52a8088db --- .../AppNotificationSettingsTest.java | 59 ++++++++----------- .../ChannelNotificationSettingsTest.java | 20 +++++-- .../ZenModeSettingsIntegrationTest.java | 22 +++---- 3 files changed, 49 insertions(+), 52 deletions(-) diff --git a/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java index ede4631abd6..19b1360247d 100644 --- a/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java +++ b/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java @@ -41,6 +41,7 @@ import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; import androidx.test.InstrumentationRegistry; import androidx.test.espresso.intent.Intents; @@ -55,7 +56,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class AppNotificationSettingsTest { + private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard"; + private UiDevice mUiDevice; private Context mTargetContext; private Instrumentation mInstrumentation; @@ -68,9 +71,14 @@ public class AppNotificationSettingsTest { private NotificationChannel mUngroupedChannel; @Before - public void setUp() { + public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); mTargetContext = mInstrumentation.getTargetContext(); + + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + mUiDevice.wakeUp(); + mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND); + mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE); mGroup1 = new NotificationChannelGroup(this.getClass().getName() + "1", "group1"); @@ -87,7 +95,8 @@ public class AppNotificationSettingsTest { @Test public void launchNotificationSetting_shouldNotHaveAppInfoLink() { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()); + .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); @@ -99,60 +108,38 @@ public class AppNotificationSettingsTest { @Test public void launchNotificationSetting_showGroupsWithMultipleChannels() { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()); + .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); onView(allOf(withText(mGroup1.getName().toString()))).check( matches(isDisplayed())); - try { - onView(allOf(withText(mGroup1Channel1.getName().toString()))) - .check(matches(isDisplayed())); - fail("Channel erroneously appearing"); - } catch (Exception e) { - // expected - } - // links to group page - Intents.init(); - onView(allOf(withText(mGroup1.getName().toString()))).perform(click()); - intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT, - ChannelGroupNotificationSettings.class.getName()))); - Intents.release(); + onView(allOf(withText(mGroup1Channel1.getName().toString()))).check( + matches(isDisplayed())); + onView(allOf(withText(mGroup1Channel2.getName().toString()))).check( + matches(isDisplayed())); } @Test public void launchNotificationSetting_showUngroupedChannels() { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()); + .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); onView(allOf(withText(mUngroupedChannel.getName().toString()))) .check(matches(isDisplayed())); - // links directly to channel page - Intents.init(); - onView(allOf(withText(mUngroupedChannel.getName().toString()))).perform(click()); - intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT, ChannelNotificationSettings.class.getName()))); - Intents.release(); } @Test public void launchNotificationSetting_showGroupsWithOneChannel() { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()); + .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); + onView(allOf(withText(mGroup2.getName().toString()))) + .check(matches(isDisplayed())); onView(allOf(withText(mGroup2Channel1.getName().toString()))) .check(matches(isDisplayed())); - try { - onView(allOf(withText(mGroup2.getName().toString()))).check( - matches(isDisplayed())); - fail("Group erroneously appearing"); - } catch (Exception e) { - // expected - } - - // links directly to channel page - Intents.init(); - onView(allOf(withText(mGroup2Channel1.getName().toString()))).perform(click()); - intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT, ChannelNotificationSettings.class.getName()))); - Intents.release(); } private NotificationChannel createChannel(NotificationChannelGroup group, diff --git a/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java index f7a5a82327b..9a3a99455c9 100644 --- a/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java +++ b/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java @@ -36,6 +36,7 @@ import android.content.Intent; import android.os.Process; import android.os.ServiceManager; import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -48,17 +49,23 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class ChannelNotificationSettingsTest { + private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard"; + private UiDevice mUiDevice; private Context mTargetContext; private Instrumentation mInstrumentation; private NotificationChannel mNotificationChannel; private NotificationManager mNm; @Before - public void setUp() { + public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); mTargetContext = mInstrumentation.getTargetContext(); + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + mUiDevice.wakeUp(); + mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND); + mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE); mNotificationChannel = new NotificationChannel(this.getClass().getName(), this.getClass().getName(), IMPORTANCE_MIN); @@ -69,7 +76,8 @@ public class ChannelNotificationSettingsTest { public void launchNotificationSetting_shouldNotCrash() { final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) - .putExtra(Settings.EXTRA_CHANNEL_ID, mNotificationChannel.getId()); + .putExtra(Settings.EXTRA_CHANNEL_ID, mNotificationChannel.getId()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); onView(allOf(withText(mNotificationChannel.getName().toString()))).check( @@ -90,12 +98,12 @@ public class ChannelNotificationSettingsTest { final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName()) - .putExtra(Settings.EXTRA_CHANNEL_ID, blocked.getId()); + .putExtra(Settings.EXTRA_CHANNEL_ID, blocked.getId()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mInstrumentation.startActivitySync(intent); - onView(allOf(withText("Off"), isDisplayed())).check(matches(isDisplayed())); - onView(allOf(withText("Android is blocking this category of notifications from" - + " appearing on this device"))).check(matches(isDisplayed())); + onView(allOf(withText("At your request, Android is blocking this category of notifications" + + " from appearing on this device"))).check(matches(isDisplayed())); try { onView(allOf(withText("On the lock screen"))).check(matches(isDisplayed())); diff --git a/tests/unit/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java b/tests/unit/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java index 2fe4074928b..4120a07f7a1 100644 --- a/tests/unit/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java +++ b/tests/unit/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java @@ -37,27 +37,29 @@ public class ZenModeSettingsIntegrationTest { @Test public void testZenModeSettingsPreferences() { launchZenSettings(); - onView(withText("Behavior")).check(matches(isDisplayed())); - onView(withText("Turn on automatically")).check(matches(isDisplayed())); + onView(withText("Calls")).check(matches(isDisplayed())); + onView(withText("SMS, MMS, and messaging apps")).check(matches(isDisplayed())); + onView(withText("Restrict notifications")).check(matches(isDisplayed())); + onView(withText("Duration")).check(matches(isDisplayed())); + onView(withText("Schedules")).check(matches(isDisplayed())); } @Test public void testZenModeBehaviorPreferences() { launchZenBehaviorSettings(); - onView(withText("Alarms")).check(matches(isDisplayed())); - onView(withText("Media and system feedback")).check(matches(isDisplayed())); - onView(withText("Reminders")).check(matches(isDisplayed())); - onView(withText("Events")).check(matches(isDisplayed())); - onView(withText("Messages")).check(matches(isDisplayed())); onView(withText("Calls")).check(matches(isDisplayed())); - onView(withText("Repeat callers")).check(matches(isDisplayed())); + onView(withText("SMS, MMS, and messaging apps")).check(matches(isDisplayed())); + onView(withText("Restrict notifications")).check(matches(isDisplayed())); + onView(withText("Duration")).check(matches(isDisplayed())); + onView(withText("Schedules")).check(matches(isDisplayed())); } @Test public void testZenModeAutomationPreferences() { launchZenAutomationSettings(); - onView(withText("Weekend")).check(matches(isDisplayed())); - onView(withText("Add rule")).check(matches(isDisplayed())); + onView(withText("Sleeping")).check(matches(isDisplayed())); + onView(withText("Event")).check(matches(isDisplayed())); + onView(withText("Add more")).check(matches(isDisplayed())); } private void launchZenSettings() { From 9e50419c75a515ec484a9b526e97ce4dcf4995b1 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Thu, 21 Feb 2019 15:17:37 -0800 Subject: [PATCH 13/17] Remove NFC Slice jank The NFC Slice would jank on enable and disable, because of the intent filter it registered with SysUI. The intent filter would broadcast an update for four states: 1) On 2) Off 3) Turning On 4) Turning off The first two caused no problems. The third and fourth caused jank, since when clicked, the switch in the NFC slice would turn on / off asynchronously - that is, it turned on or off based on the previous state of the switch, rather than on the actual value of NFC. It does this to feel fluid in the app in which it is rendered. From the off state, the order of events is: 1. Switch clicked 2. Switch animates on 2. Background intent is fired to settings to turn on Nfc (happens at the same time as animation) 3. Settings calls the NFC enable API 4. A broadcast for Turning On is sent 5. The receiver in SysUI gets the broadcast and forwards it to settings 6. Settings tells the Slice to make sure it is up to date 7. The Slice checks for the current value - IMPORTANTLY - which is currently off, it is only in the process of being enabled. 8. The Slice flips back off 9. Nfc finishes getting enabled in the background 10. The framework pushes the NFC ON broadcast 11. SysUI gets the broadcast, and forwards it to settings 12. Settings tells the slice to update 13. The slice checks again and finds that NFC is on, flipping on. This CL creates a new background slice worker for NFC and registers the intent filter there, rather than in SysUI. When the background worker gets the broadcast, it checks if it is in state 3/4, and if so, it drops the update silently. Fixes: 115737701 Test: robotests Change-Id: I17043828ad3a67a2a5acdf5c75d9cc51ff7e91d0 --- res/layout/settings_panel.xml | 3 +- .../settings/nfc/NfcPreferenceController.java | 97 ++++++++++++++++--- .../settings/slices/CustomSliceable.java | 12 --- .../slices/SettingsSliceProvider.java | 9 +- .../slices/SliceBackgroundWorker.java | 5 +- .../android/settings/slices/Sliceable.java | 12 +++ .../nfc/NfcPreferenceControllerTest.java | 70 +++++++++++++ .../slices/SettingsSliceProviderTest.java | 15 +++ .../testutils/FakeToggleController.java | 28 ++++++ 9 files changed, 220 insertions(+), 31 deletions(-) diff --git a/res/layout/settings_panel.xml b/res/layout/settings_panel.xml index aec898c99c6..3405ef0d844 100644 --- a/res/layout/settings_panel.xml +++ b/res/layout/settings_panel.xml @@ -16,4 +16,5 @@ \ No newline at end of file + android:layout_width="match_parent" + android:animateLayoutChanges="true"/> \ No newline at end of file diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java index 04f288d721b..2ca3b23daea 100644 --- a/src/com/android/settings/nfc/NfcPreferenceController.java +++ b/src/com/android/settings/nfc/NfcPreferenceController.java @@ -15,20 +15,26 @@ */ package com.android.settings.nfc; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.content.IntentFilter; +import android.net.Uri; import android.nfc.NfcAdapter; import android.provider.Settings; - +import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.slices.SliceBackgroundWorker; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; +import java.io.IOException; + public class NfcPreferenceController extends TogglePreferenceController implements LifecycleObserver, OnResume, OnPause { @@ -51,8 +57,7 @@ public class NfcPreferenceController extends TogglePreferenceController return; } - final SwitchPreference switchPreference = - (SwitchPreference) screen.findPreference(getPreferenceKey()); + final SwitchPreference switchPreference = screen.findPreference(getPreferenceKey()); mNfcEnabler = new NfcEnabler(mContext, switchPreference); @@ -86,14 +91,6 @@ public class NfcPreferenceController extends TogglePreferenceController : UNSUPPORTED_ON_DEVICE; } - @Override - public IntentFilter getIntentFilter() { - final IntentFilter filter = new IntentFilter(); - filter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); - filter.addAction(NfcAdapter.EXTRA_ADAPTER_STATE); - return filter; - } - @Override public boolean hasAsyncUpdate() { return true; @@ -104,6 +101,11 @@ public class NfcPreferenceController extends TogglePreferenceController return true; } + @Override + public Class getBackgroundWorkerClass() { + return NfcSliceWorker.class; + } + @Override public void onResume() { if (mAirplaneModeObserver != null) { @@ -135,4 +137,77 @@ public class NfcPreferenceController extends TogglePreferenceController Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC); } + + /** + * Listener for background changes to NFC. + * + *

+ * Listen to broadcasts from {@link NfcAdapter}. The worker will call notify changed on the + * NFC Slice only when the following extras are present in the broadcast: + *

    + *
  • {@link NfcAdapter#STATE_ON}
  • + *
  • {@link NfcAdapter#STATE_OFF}
  • + *
+ */ + public static class NfcSliceWorker extends SliceBackgroundWorker { + + private static final String TAG = "NfcSliceWorker"; + + private static final IntentFilter NFC_FILTER = + new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + + private NfcUpdateReceiver mUpdateObserver; + + public NfcSliceWorker(Context context, Uri uri) { + super(context, uri); + mUpdateObserver = new NfcUpdateReceiver(this); + } + + @Override + protected void onSlicePinned() { + getContext().registerReceiver(mUpdateObserver, NFC_FILTER); + } + + @Override + protected void onSliceUnpinned() { + getContext().unregisterReceiver(mUpdateObserver); + } + + @Override + public void close() throws IOException { + mUpdateObserver = null; + } + + public void updateSlice() { + notifySliceChange(); + } + + public class NfcUpdateReceiver extends BroadcastReceiver { + + private final int NO_EXTRA = -1; + + private final NfcSliceWorker mSliceBackgroundWorker; + + public NfcUpdateReceiver(NfcSliceWorker sliceWorker) { + mSliceBackgroundWorker = sliceWorker; + } + + @Override + public void onReceive(Context context, Intent intent) { + final int nfcStateExtra = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, + NO_EXTRA); + + // Do nothing if state change is empty, or an intermediate step. + if ( (nfcStateExtra == NO_EXTRA) + || (nfcStateExtra == NfcAdapter.STATE_TURNING_ON) + || (nfcStateExtra == NfcAdapter.STATE_TURNING_OFF)) { + Log.d(TAG, "Transitional update, dropping broadcast"); + return; + } + + Log.d(TAG, "Nfc broadcast received, updating Slice."); + mSliceBackgroundWorker.updateSlice(); + } + } + } } diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java index b48f22a5237..0b97bedc54f 100644 --- a/src/com/android/settings/slices/CustomSliceable.java +++ b/src/com/android/settings/slices/CustomSliceable.java @@ -83,18 +83,6 @@ public interface CustomSliceable extends Sliceable { */ Intent getIntent(); - /** - * Settings Slices which require background work, such as updating lists should implement a - * {@link SliceBackgroundWorker} and return it here. An example of background work is updating - * a list of Wifi networks available in the area. - * - * @return a {@link Class} to perform background work for the - * slice. - */ - default Class getBackgroundWorkerClass() { - return null; - } - /** * Standardize the intents returned to indicate actions by the Slice. *

diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 5c662e5c7e0..397b2fc631c 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -153,7 +153,7 @@ public class SettingsSliceProvider extends SliceProvider { if (filter != null) { registerIntentToUri(filter, sliceUri); } - ThreadUtils.postOnMainThread(() -> startBackgroundWorker(sliceable)); + ThreadUtils.postOnMainThread(() -> startBackgroundWorker(sliceable, sliceUri)); return; } @@ -326,20 +326,19 @@ public class SettingsSliceProvider extends SliceProvider { } } - private void startBackgroundWorker(CustomSliceable sliceable) { + private void startBackgroundWorker(Sliceable sliceable, Uri uri) { final Class workerClass = sliceable.getBackgroundWorkerClass(); if (workerClass == null) { return; } - final Uri uri = sliceable.getUri(); if (mPinnedWorkers.containsKey(uri)) { return; } Log.d(TAG, "Starting background worker for: " + uri); final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance( - getContext(), sliceable); + getContext(), sliceable, uri); mPinnedWorkers.put(uri, worker); worker.onSlicePinned(); } @@ -397,6 +396,8 @@ public class SettingsSliceProvider extends SliceProvider { registerIntentToUri(filter, uri); } + ThreadUtils.postOnMainThread(() -> startBackgroundWorker(controller, uri)); + final List pinnedSlices = getContext().getSystemService( SliceManager.class).getPinnedSlices(); if (pinnedSlices.contains(uri)) { diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java index 995394e7d41..559aa711e2a 100644 --- a/src/com/android/settings/slices/SliceBackgroundWorker.java +++ b/src/com/android/settings/slices/SliceBackgroundWorker.java @@ -80,13 +80,12 @@ public abstract class SliceBackgroundWorker implements Closeable { * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link * CustomSliceable} */ - static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) { - final Uri uri = sliceable.getUri(); + static SliceBackgroundWorker getInstance(Context context, Sliceable sliceable, Uri uri) { SliceBackgroundWorker worker = getInstance(uri); if (worker == null) { final Class workerClass = sliceable.getBackgroundWorkerClass(); - worker = createInstance(context, uri, workerClass); + worker = createInstance(context.getApplicationContext(), uri, workerClass); LIVE_WORKERS.put(uri, worker); } return worker; diff --git a/src/com/android/settings/slices/Sliceable.java b/src/com/android/settings/slices/Sliceable.java index b00ab8207eb..c1661f8392a 100644 --- a/src/com/android/settings/slices/Sliceable.java +++ b/src/com/android/settings/slices/Sliceable.java @@ -91,4 +91,16 @@ public interface Sliceable { final String toast = context.getString(R.string.copyable_slice_toast, messageTitle); Toast.makeText(context, toast, Toast.LENGTH_SHORT).show(); } + + /** + * Settings Slices which require background work, such as updating lists should implement a + * {@link SliceBackgroundWorker} and return it here. An example of background work is updating + * a list of Wifi networks available in the area. + * + * @return a {@link Class} to perform background work for the + * slice. + */ + default Class getBackgroundWorkerClass() { + return null; + } } diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java index 8883ddf7e3a..e3672c92dc9 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java @@ -19,10 +19,13 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.nfc.NfcAdapter; import android.nfc.NfcManager; import android.os.UserManager; @@ -31,6 +34,10 @@ import android.provider.Settings; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.android.settings.nfc.NfcPreferenceController.NfcSliceWorker; +import com.android.settings.nfc.NfcPreferenceController.NfcSliceWorker.NfcUpdateReceiver; +import com.android.settings.slices.SliceBuilderUtils; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -246,4 +253,67 @@ public class NfcPreferenceControllerTest { assertThat(mNfcController.mAirplaneModeObserver).isNull(); } + + @Test + public void ncfSliceWorker_nfcBroadcast_noExtra_sliceDoesntUpdate() { + final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri())); + final NfcUpdateReceiver receiver = worker.new NfcUpdateReceiver(worker); + final Intent triggerIntent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + + receiver.onReceive(mContext, triggerIntent); + + verify(worker, times(0)).updateSlice(); + } + + @Test + public void ncfSliceWorker_nfcBroadcast_turningOn_sliceDoesntUpdate() { + final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri())); + final NfcUpdateReceiver receiver = worker.new NfcUpdateReceiver(worker); + final Intent triggerIntent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + triggerIntent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_TURNING_ON); + + receiver.onReceive(mContext, triggerIntent); + + verify(worker, times(0)).updateSlice(); + } + + @Test + public void ncfSliceWorker_nfcBroadcast_turningOff_sliceDoesntUpdate() { + final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri())); + final NfcUpdateReceiver receiver = worker.new NfcUpdateReceiver(worker); + final Intent triggerIntent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + triggerIntent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_TURNING_OFF); + + receiver.onReceive(mContext, triggerIntent); + + verify(worker, times(0)).updateSlice(); + } + + @Test + public void ncfSliceWorker_nfcBroadcast_nfcOn_sliceUpdates() { + final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri())); + final NfcUpdateReceiver receiver = worker.new NfcUpdateReceiver(worker); + final Intent triggerIntent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + triggerIntent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_ON); + + receiver.onReceive(mContext, triggerIntent); + + verify(worker).updateSlice(); + } + + @Test + public void ncfSliceWorker_nfcBroadcast_nfcOff_sliceUpdates() { + final NfcSliceWorker worker = spy(new NfcSliceWorker(mContext, getDummyUri())); + final NfcUpdateReceiver receiver = worker.new NfcUpdateReceiver(worker); + final Intent triggerIntent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + triggerIntent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_OFF); + + receiver.onReceive(mContext, triggerIntent); + + verify(worker).updateSlice(); + } + + private Uri getDummyUri() { + return SliceBuilderUtils.getUri("action/nfc", false); + } } diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index 726e4bdf300..a693f349894 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -64,6 +64,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -183,6 +184,20 @@ public class SettingsSliceProviderTest { verify(mProvider).registerIntentToUri(eq(FakeToggleController.INTENT_FILTER), eq(uri)); } + @Test + public void loadSlice_registersBackgroundListener() { + insertSpecialCase(KEY); + final Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false); + + mProvider.loadSlice(uri); + + Robolectric.flushForegroundThreadScheduler(); + Robolectric.flushBackgroundThreadScheduler(); + + assertThat(mProvider.mPinnedWorkers.get(uri).getClass()) + .isEqualTo(FakeToggleController.TestWorker.class); + } + @Test public void testLoadSlice_doesNotCacheWithoutPin() { insertSpecialCase(KEY); diff --git a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java index d1677cd7382..e7854874c54 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java @@ -19,10 +19,14 @@ package com.android.settings.testutils; import android.content.Context; import android.content.IntentFilter; +import android.net.Uri; import android.net.wifi.WifiManager; import android.provider.Settings; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.slices.SliceBackgroundWorker; + +import java.io.IOException; public class FakeToggleController extends TogglePreferenceController { @@ -70,6 +74,11 @@ public class FakeToggleController extends TogglePreferenceController { return true; } + @Override + public Class getBackgroundWorkerClass() { + return TestWorker.class; + } + @Override public boolean hasAsyncUpdate() { return mIsAsyncUpdate; @@ -78,4 +87,23 @@ public class FakeToggleController extends TogglePreferenceController { public void setAsyncUpdate(boolean isAsyncUpdate) { mIsAsyncUpdate = isAsyncUpdate; } + + public static class TestWorker extends SliceBackgroundWorker { + + public TestWorker(Context context, Uri uri) { + super(context, uri); + } + + @Override + protected void onSlicePinned() { + } + + @Override + protected void onSliceUnpinned() { + } + + @Override + public void close() throws IOException { + } + } } From 71d5e90a6ef345617876b17d7a9f7b37e1b32cb3 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 26 Feb 2019 10:42:10 -0800 Subject: [PATCH 14/17] Include uid in device admin pref id. Fixes: 124979213 Test: robotests Change-Id: I50114db79e9b5278bc916fbbba6353c5f19df24f --- .../deviceadmin/DeviceAdminListItem.java | 25 +++++--- .../DeviceAdminListPreferenceController.java | 24 +++++++- .../deviceadmin/DeviceAdminUtils.java | 58 ------------------- .../deviceadmin/DeviceAdminListItemTest.java | 2 +- 4 files changed, 39 insertions(+), 70 deletions(-) delete mode 100644 src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItem.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItem.java index 305281c4620..370a4dfe12f 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItem.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItem.java @@ -30,6 +30,7 @@ class DeviceAdminListItem implements Comparable { private static final String TAG = "DeviceAdminListItem"; + private final UserHandle mUserHandle; private final String mKey; private final DeviceAdminInfo mInfo; private final CharSequence mName; @@ -39,7 +40,8 @@ class DeviceAdminListItem implements Comparable { public DeviceAdminListItem(Context context, DeviceAdminInfo info) { mInfo = info; - mKey = mInfo.getComponent().flattenToString(); + mUserHandle = new UserHandle(getUserIdFromDeviceAdminInfo(mInfo)); + mKey = mUserHandle.getIdentifier() + "@" + mInfo.getComponent().flattenToString(); mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); final PackageManager pm = context.getPackageManager(); mName = mInfo.loadLabel(pm); @@ -48,8 +50,7 @@ class DeviceAdminListItem implements Comparable { } catch (Resources.NotFoundException exception) { Log.w(TAG, "Setting description to null because can't find resource: " + mKey); } - mIcon = pm.getUserBadgedIcon(mInfo.loadIcon(pm), - new UserHandle(DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo))); + mIcon = pm.getUserBadgedIcon(mInfo.loadIcon(pm), mUserHandle); } @Override @@ -70,8 +71,7 @@ class DeviceAdminListItem implements Comparable { } public boolean isActive() { - return mDPM.isAdminActiveAsUser(mInfo.getComponent(), - DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + return mDPM.isAdminActiveAsUser(mInfo.getComponent(), getUserIdFromDeviceAdminInfo(mInfo)); } public Drawable getIcon() { @@ -79,16 +79,25 @@ class DeviceAdminListItem implements Comparable { } public boolean isEnabled() { - return !mDPM.isRemovingAdmin(mInfo.getComponent(), - DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + return !mDPM.isRemovingAdmin(mInfo.getComponent(), getUserIdFromDeviceAdminInfo(mInfo)); } public UserHandle getUser() { - return new UserHandle(DeviceAdminUtils.getUserIdFromDeviceAdminInfo(mInfo)); + return new UserHandle(getUserIdFromDeviceAdminInfo(mInfo)); } public Intent getLaunchIntent(Context context) { return new Intent(context, DeviceAdminAdd.class) .putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mInfo.getComponent()); } + + /** + * Extracts the user id from a device admin info object. + * + * @param adminInfo the device administrator info. + * @return identifier of the user associated with the device admin. + */ + private static int getUserIdFromDeviceAdminInfo(DeviceAdminInfo adminInfo) { + return UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid); + } } diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java index 319d62f66c3..7b139d9770a 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java @@ -53,6 +53,9 @@ import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.FooterPreferenceMixinCompat; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -249,8 +252,7 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle Log.w(TAG, "Unable to load component: " + activeAdmin); continue; } - final DeviceAdminInfo deviceAdminInfo = DeviceAdminUtils.createDeviceAdminInfo( - mContext, ai); + final DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo(mContext, ai); if (deviceAdminInfo == null) { continue; } @@ -286,7 +288,7 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle && alreadyAddedComponents.contains(riComponentName)) { continue; } - DeviceAdminInfo deviceAdminInfo = DeviceAdminUtils.createDeviceAdminInfo( + DeviceAdminInfo deviceAdminInfo = createDeviceAdminInfo( mContext, resolveInfo.activityInfo); // add only visible ones (note: active admins are added regardless of visibility) if (deviceAdminInfo != null && deviceAdminInfo.isVisible()) { @@ -297,4 +299,20 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle } } } + + /** + * Creates a device admin info object for the resolved intent that points to the component of + * the device admin. + * + * @param ai ActivityInfo for the admin component. + * @return new {@link DeviceAdminInfo} object or null if there was an error. + */ + private static DeviceAdminInfo createDeviceAdminInfo(Context context, ActivityInfo ai) { + try { + return new DeviceAdminInfo(context, ai); + } catch (XmlPullParserException | IOException e) { + Log.w(TAG, "Skipping " + ai, e); + } + return null; + } } diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java deleted file mode 100644 index 13d9d20bece..00000000000 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminUtils.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 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.applications.specialaccess.deviceadmin; - -import android.app.admin.DeviceAdminInfo; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.os.UserHandle; -import android.util.Log; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -public class DeviceAdminUtils { - - private static final String TAG = "DeviceAdminUtils"; - - /** - * Creates a device admin info object for the resolved intent that points to the component of - * the device admin. - * - * @param ai ActivityInfo for the admin component. - * @return new {@link DeviceAdminInfo} object or null if there was an error. - */ - public static DeviceAdminInfo createDeviceAdminInfo(Context context, ActivityInfo ai) { - try { - return new DeviceAdminInfo(context, ai); - } catch (XmlPullParserException | IOException e) { - Log.w(TAG, "Skipping " + ai, e); - } - return null; - } - - /** - * Extracts the user id from a device admin info object. - * - * @param adminInfo the device administrator info. - * @return identifier of the user associated with the device admin. - */ - public static int getUserIdFromDeviceAdminInfo(DeviceAdminInfo adminInfo) { - return UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid); - } -} diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java index 17703e334dd..7392fb1376a 100644 --- a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListItemTest.java @@ -67,7 +67,7 @@ public class DeviceAdminListItemTest { DeviceAdminListItem item = new DeviceAdminListItem(mContext, mDeviceAdminInfo); - assertThat(item.getKey()).isEqualTo(cn.flattenToShortString()); + assertThat(item.getKey()).isEqualTo("0@" + cn.flattenToShortString()); assertThat(item.getName()).isEqualTo(label); assertThat(item.getDescription()).isEqualTo(description); } From 7c261409d2e25eb0e943976ddee8092a65db059e Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 26 Feb 2019 13:06:23 -0800 Subject: [PATCH 15/17] Make Serial number preference a copyable slice. Fixes: 73769621 Test: robotests Change-Id: Ic20d8865bc26c1acc7db74e665f92fe388d62f74 --- .../SerialNumberPreferenceController.java | 12 ++++ .../contextualcards/ContextualCardLoader.java | 1 + .../slices/SliceBroadcastReceiver.java | 2 +- .../SerialNumberPreferenceControllerTest.java | 60 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceControllerTest.java diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java index 4485c53d7ae..01cd5f3b9e4 100644 --- a/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceController.java @@ -21,6 +21,7 @@ import android.os.Build; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.slices.Sliceable; public class SerialNumberPreferenceController extends BasePreferenceController { @@ -39,6 +40,17 @@ public class SerialNumberPreferenceController extends BasePreferenceController { return true; } + @Override + public boolean isCopyableSlice() { + return true; + } + + @Override + public void copy() { + Sliceable.setCopyContent(mContext, getSummary(), + mContext.getText(R.string.status_serial_number)); + } + @Override public CharSequence getSummary() { return Build.getSerial(); diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java index 42e18edd689..d6ea6ca668a 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java @@ -23,6 +23,7 @@ import static com.android.settings.slices.CustomSliceRegistry.NOTIFICATION_CHANN import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.text.format.DateUtils; diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index 2a9b491713c..b2ea5830fe2 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -197,7 +197,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { return; } - ((Sliceable) controller).copy(); + controller.copy(); } /** diff --git a/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceControllerTest.java new file mode 100644 index 00000000000..c2ae4af703e --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/hardwareinfo/SerialNumberPreferenceControllerTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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.deviceinfo.hardwareinfo; + + +import static com.google.common.truth.Truth.assertThat; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Build; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class SerialNumberPreferenceControllerTest { + + private Context mContext; + private SerialNumberPreferenceController mController; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mController = new SerialNumberPreferenceController(mContext, "test"); + } + + @Test + public void isCopyableSlice() { + assertThat(mController.isSliceable()).isTrue(); + assertThat(mController.isCopyableSlice()).isTrue(); + } + + @Test + public void copy_shouldPutSerialNumberToClipBoard() { + mController.copy(); + + final ClipboardManager clipboardManager = mContext.getSystemService(ClipboardManager.class); + final ClipData data = clipboardManager.getPrimaryClip(); + + assertThat(data.getItemAt(0).getText().toString()).contains(Build.getSerial()); + } +} From db7fe5e5f7b94bde5dd56fcdcd5a07abe1f53a43 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Tue, 26 Feb 2019 14:14:56 -0800 Subject: [PATCH 16/17] Fix panel bugs Add unique task affinity so the panel activity always opens alone. Apparently the launchMode="singleTop" was insufficient. Test: manual app Fixes: 126385021 Fixes: 126386586 Fixes: 126326438 Change-Id: I775e84701d006cfbe0d9ddfff83669b3f8487b33 --- AndroidManifest.xml | 1 + res/layout-land/panel_layout.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6724ff5355d..a5586f7955e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3009,6 +3009,7 @@ android:theme="@style/Theme.BottomDialog" android:excludeFromRecents="true" android:launchMode="singleTop" + android:taskAffinity=".panel.SettingsPanelActivity" android:exported="true"> diff --git a/res/layout-land/panel_layout.xml b/res/layout-land/panel_layout.xml index 3975bfeaa3f..049fd0b579b 100644 --- a/res/layout-land/panel_layout.xml +++ b/res/layout-land/panel_layout.xml @@ -20,7 +20,7 @@ android:orientation="vertical"> Date: Tue, 26 Feb 2019 15:45:17 -0800 Subject: [PATCH 17/17] Guard NPE in RingtonePrefController Fixes: 126416474 Test: robotests Change-Id: I02d0279ae107e7c03668849beaea8aa0463b4da6 --- .../RingtonePreferenceControllerBase.java | 17 +++++++++----- .../RingtonePreferenceControllerBaseTest.java | 22 ++++++++++++++----- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/notification/RingtonePreferenceControllerBase.java b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java index 7b37855c6f7..733d0d937d7 100644 --- a/src/com/android/settings/notification/RingtonePreferenceControllerBase.java +++ b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java @@ -50,13 +50,18 @@ public abstract class RingtonePreferenceControllerBase extends AbstractPreferenc } private void updateSummary(Preference preference) { - Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(mContext, getRingtoneType()); - final CharSequence summary = Ringtone.getTitle( - mContext, ringtoneUri, false /* followSettingsUri */, true /* allowRemote */); + final Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri( + mContext, getRingtoneType()); + + final CharSequence summary; + if (ringtoneUri == null) { + summary = null; + } else { + summary = Ringtone.getTitle( + mContext, ringtoneUri, false /* followSettingsUri */, true /* allowRemote */); + } if (summary != null) { - ThreadUtils.postOnMainThread(() -> { - preference.setSummary(summary); - }); + ThreadUtils.postOnMainThread(() -> preference.setSummary(summary)); } } diff --git a/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java index f22a78225a2..2fb1738f25a 100644 --- a/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java +++ b/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java @@ -20,31 +20,31 @@ import static com.google.common.truth.Truth.assertThat; 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 android.content.Context; import android.media.RingtoneManager; +import android.provider.Settings; import androidx.preference.Preference; 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; @RunWith(RobolectricTestRunner.class) public class RingtonePreferenceControllerBaseTest { - @Mock private Context mContext; private RingtonePreferenceControllerBase mController; @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; mController = new RingtonePreferenceControllerBaseTestable(mContext); } @@ -56,14 +56,26 @@ public class RingtonePreferenceControllerBaseTest { @Test public void updateState_shouldSetSummary() { Preference preference = mock(Preference.class); + Settings.System.putString(mContext.getContentResolver(), Settings.System.RINGTONE, + "content://test/ringtone"); mController.updateState(preference); verify(preference).setSummary(anyString()); } + @Test + public void updateState_nullRingtone_shouldNotGetTitle() { + Preference preference = mock(Preference.class); + Settings.System.putString(mContext.getContentResolver(), Settings.System.RINGTONE, null); + + mController.updateState(preference); + + verify(preference, never()).setSummary(anyString()); + } + private class RingtonePreferenceControllerBaseTestable - extends RingtonePreferenceControllerBase { + extends RingtonePreferenceControllerBase { RingtonePreferenceControllerBaseTestable(Context context) { super(context); }