From c2f8ab587e8c4c1b47091a3c45ef1e45ba62cea2 Mon Sep 17 00:00:00 2001 From: jeffreyhuang Date: Wed, 25 Oct 2017 14:44:44 -0700 Subject: [PATCH 01/13] Popup a dialog to display user IMEI information - Add new dialog fragment to show imei information - Create layout files for the dialog - Create a new controller to launch the dialog activity - Create a new controller to update the contents of the dialog - Deprecate old files that are no longer used in about phone v2 Bug: 36458278 Test: make RunSettingsRoboTests -j40 Change-Id: I6d4273726e2271049a0ab69c2375dac0ac393e04 --- res/layout/dialog_imei_info.xml | 114 +++++++++++++ res/values/strings.xml | 9 + res/values/styles.xml | 10 ++ res/xml/device_info_settings_v2.xml | 12 +- .../android/settings/DeviceInfoSettings.java | 7 +- .../ImeiInfoPreferenceController.java | 5 + .../settings/deviceinfo/ImeiInformation.java | 6 +- .../AbstractImeiInfoPreferenceController.java | 99 +++++++++++ .../imei/ImeiInfoDialogController.java | 160 ++++++++++++++++++ .../imei/ImeiInfoDialogFragment.java | 94 ++++++++++ .../ImeiInfoDualSimPreferenceController.java | 57 +++++++ .../imei/ImeiInfoPreferenceControllerV2.java | 55 ++++++ ...tractImeiInfoPreferenceControllerTest.java | 143 ++++++++++++++++ .../imei/ImeiInfoDialogControllerTest.java | 133 +++++++++++++++ ...eiInfoDualSimPreferenceControllerTest.java | 89 ++++++++++ .../ImeiInfoPreferenceControllerV2Test.java | 105 ++++++++++++ 16 files changed, 1093 insertions(+), 5 deletions(-) create mode 100644 res/layout/dialog_imei_info.xml create mode 100644 src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java create mode 100644 src/com/android/settings/deviceinfo/imei/ImeiInfoDialogFragment.java create mode 100644 src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2Test.java diff --git a/res/layout/dialog_imei_info.xml b/res/layout/dialog_imei_info.xml new file mode 100644 index 00000000000..b19d336410e --- /dev/null +++ b/res/layout/dialog_imei_info.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index f0721fc7dcd..fb79df5fbf3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2661,6 +2661,10 @@ Unmount USB storage, view available storage Unmount SD card, view available storage + + IMEI (sim slot 1) + + IMEI (sim slot 2) IMEI @@ -2677,6 +2681,10 @@ MSID PRL version + + MEID (sim slot 1) + + MEID (sim slot 2) MEID @@ -6555,6 +6563,7 @@ pay, tap, payments backup, back up gesture + imei, meid diff --git a/res/values/styles.xml b/res/values/styles.xml index c9ef22cfb97..8815bb3c762 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -478,4 +478,14 @@ @dimen/search_bar_text_size + + + + diff --git a/res/xml/device_info_settings_v2.xml b/res/xml/device_info_settings_v2.xml index 0553f1ebc5c..794a12bf866 100644 --- a/res/xml/device_info_settings_v2.xml +++ b/res/xml/device_info_settings_v2.xml @@ -40,10 +40,18 @@ android:title="@string/hardware_info" android:summary="@string/summary_placeholder"/> - + + + + diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java index 4479eaadb81..5a5bec0f3e7 100644 --- a/src/com/android/settings/DeviceInfoSettings.java +++ b/src/com/android/settings/DeviceInfoSettings.java @@ -32,6 +32,8 @@ import com.android.settings.deviceinfo.DeviceModelPreferenceController; import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController; import com.android.settings.deviceinfo.FeedbackPreferenceController; import com.android.settings.deviceinfo.FirmwareVersionPreferenceController; +import com.android.settings.deviceinfo.imei.ImeiInfoDualSimPreferenceController; +import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2; import com.android.settings.deviceinfo.KernelVersionPreferenceController; import com.android.settings.deviceinfo.ManualPreferenceController; import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController; @@ -120,7 +122,6 @@ public class DeviceInfoSettings extends DashboardFragment implements Indexable { Activity activity, Fragment fragment, Lifecycle lifecycle) { if (FeatureFlagUtils.isEnabled(DEVICE_INFO_V2_FEATURE_FLAG)) { final List controllers = new ArrayList<>(); - // Device name // Phone number @@ -129,7 +130,9 @@ public class DeviceInfoSettings extends DashboardFragment implements Indexable { controllers.add(new DeviceModelPreferenceController(context, fragment)); - // IMEI + controllers.add(new ImeiInfoPreferenceControllerV2(context, fragment)); + + controllers.add(new ImeiInfoDualSimPreferenceController(context, fragment)); // Android version diff --git a/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java b/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java index f56473474a6..456dbfcce15 100644 --- a/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java +++ b/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java @@ -19,8 +19,13 @@ package com.android.settings.deviceinfo; import android.content.Context; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2; import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController; +/** + * deprecated in favour of {@link ImeiInfoPreferenceControllerV2} + */ +@Deprecated public class ImeiInfoPreferenceController extends AbstractSimStatusImeiInfoPreferenceController implements PreferenceControllerMixin { diff --git a/src/com/android/settings/deviceinfo/ImeiInformation.java b/src/com/android/settings/deviceinfo/ImeiInformation.java index 9d4602b55ba..9f38f1b01bd 100644 --- a/src/com/android/settings/deviceinfo/ImeiInformation.java +++ b/src/com/android/settings/deviceinfo/ImeiInformation.java @@ -22,7 +22,6 @@ import android.support.v7.preference.PreferenceScreen; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.Spannable; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -34,7 +33,12 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2; +/** + * deprecated in favor of {@link ImeiInfoPreferenceControllerV2} + */ +@Deprecated public class ImeiInformation extends SettingsPreferenceFragment { private static final String KEY_PRL_VERSION = "prl_version"; diff --git a/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceController.java b/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceController.java new file mode 100644 index 00000000000..a9871a0f76a --- /dev/null +++ b/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceController.java @@ -0,0 +1,99 @@ +/* + * 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.imei; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; + +import android.app.Fragment; +import android.content.Context; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController; + +/** + * Controller that manages preference for single and dual sim devices. + */ +public abstract class AbstractImeiInfoPreferenceController extends + AbstractSimStatusImeiInfoPreferenceController implements PreferenceControllerMixin { + + protected final boolean mIsMultiSim; + protected final TelephonyManager mTelephonyManager; + + private Preference mPreference; + private Fragment mFragment; + + public AbstractImeiInfoPreferenceController(Context context, Fragment fragment) { + super(context); + + mFragment = fragment; + mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mIsMultiSim = mTelephonyManager.getPhoneCount() > 1; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + if (mPreference == null) { + return; + } + final int phoneType = mTelephonyManager.getPhoneType(); + if (phoneType == PHONE_TYPE_CDMA) { + mPreference.setTitle(getTitleForCdmaPhone()); + mPreference.setSummary(getMeid()); + } else { + // GSM phone + mPreference.setTitle(getTitleForGsmPhone()); + mPreference.setSummary(mTelephonyManager.getImei(getSimSlot())); + } + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + + ImeiInfoDialogFragment.show(mFragment, getSimSlot(), mPreference.getTitle().toString()); + return true; + } + + /** + * @return The preference title for phones based on CDMA technology. + */ + protected abstract String getTitleForCdmaPhone(); + + /** + * @return The preference title for phones based on GSM technology. + */ + protected abstract String getTitleForGsmPhone(); + + /** + * @return The sim slot to retrieve IMEI/CDMA information about. + */ + protected abstract int getSimSlot(); + + @VisibleForTesting + String getMeid() { + return mTelephonyManager.getMeid(getSimSlot()); + } +} diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java new file mode 100644 index 00000000000..542b630725c --- /dev/null +++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java @@ -0,0 +1,160 @@ +/* + * 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.imei; + +import android.content.Context; +import android.content.res.Resources; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.TtsSpan; + +import com.android.internal.telephony.PhoneConstants; +import com.android.settings.R; + +import java.util.List; + +public class ImeiInfoDialogController { + + @VisibleForTesting + static final int ID_PRL_VERSION_VALUE = R.id.prl_version_value; + private static final int ID_MIN_NUMBER_LABEL = R.id.min_number_label; + @VisibleForTesting + static final int ID_MIN_NUMBER_VALUE = R.id.min_number_value; + @VisibleForTesting + static final int ID_MEID_NUMBER_VALUE = R.id.meid_number_value; + @VisibleForTesting + static final int ID_ICC_ID_LABEL = R.id.icc_id_label; + @VisibleForTesting + static final int ID_ICC_ID_VALUE = R.id.icc_id_value; + @VisibleForTesting + static final int ID_IMEI_VALUE = R.id.imei_value; + @VisibleForTesting + static final int ID_IMEI_SV_VALUE = R.id.imei_sv_value; + @VisibleForTesting + static final int ID_CDMA_SETTINGS = R.id.cdma_settings; + @VisibleForTesting + static final int ID_GSM_SETTINGS = R.id.gsm_settings; + + private static CharSequence getTextAsDigits(CharSequence text) { + if (TextUtils.isDigitsOnly(text)) { + final Spannable spannable = new SpannableStringBuilder(text); + final TtsSpan span = new TtsSpan.DigitsBuilder(text.toString()).build(); + spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text = spannable; + } + return text; + } + + private final ImeiInfoDialogFragment mDialog; + private final TelephonyManager mTelephonyManager; + private final SubscriptionInfo mSubscriptionInfo; + private final int mSlotId; + + public ImeiInfoDialogController(@NonNull ImeiInfoDialogFragment dialog, int slotId) { + mDialog = dialog; + mSlotId = slotId; + final Context context = dialog.getContext(); + mTelephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + mSubscriptionInfo = getSubscriptionInfo(context, slotId); + } + + /** + * Sets IMEI/MEID information based on whether the device is CDMA or GSM. + */ + public void populateImeiInfo() { + if (mSubscriptionInfo == null) { + return; + } + if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { + updateDialogForCdmaPhone(); + } else { + updateDialogForGsmPhone(); + } + } + + private void updateDialogForCdmaPhone() { + final Resources res = mDialog.getContext().getResources(); + mDialog.setText(ID_MEID_NUMBER_VALUE, getMeid()); + mDialog.setText(ID_MIN_NUMBER_VALUE, + mTelephonyManager.getCdmaMin(mSubscriptionInfo.getSubscriptionId())); + + if (res.getBoolean(R.bool.config_msid_enable)) { + mDialog.setText(ID_MIN_NUMBER_LABEL, + res.getString(R.string.status_msid_number)); + } + + mDialog.setText(ID_PRL_VERSION_VALUE, getCdmaPrlVersion()); + + if (isCdmaLteEnabled()) { + // Show ICC ID and IMEI for LTE device + mDialog.setText(ID_ICC_ID_VALUE, mSubscriptionInfo.getIccId()); + mDialog.setText(ID_IMEI_VALUE, + getTextAsDigits(mTelephonyManager.getImei(mSlotId))); + mDialog.setText(ID_IMEI_SV_VALUE, + getTextAsDigits(mTelephonyManager.getDeviceSoftwareVersion(mSlotId))); + } else { + // device is not GSM/UMTS, do not display GSM/UMTS features + mDialog.removeViewFromScreen(ID_GSM_SETTINGS); + mDialog.removeViewFromScreen(ID_ICC_ID_LABEL); + mDialog.removeViewFromScreen(ID_ICC_ID_VALUE); + } + } + + private void updateDialogForGsmPhone() { + mDialog.setText(ID_IMEI_VALUE, getTextAsDigits(mTelephonyManager.getImei(mSlotId))); + mDialog.setText(ID_IMEI_SV_VALUE, + getTextAsDigits(mTelephonyManager.getDeviceSoftwareVersion(mSlotId))); + // device is not CDMA, do not display CDMA features + mDialog.removeViewFromScreen(ID_CDMA_SETTINGS); + mDialog.removeViewFromScreen(ID_ICC_ID_LABEL); + mDialog.removeViewFromScreen(ID_ICC_ID_VALUE); + } + + private SubscriptionInfo getSubscriptionInfo(Context context, int slotId) { + final List subscriptionInfoList = SubscriptionManager.from(context) + .getActiveSubscriptionInfoList(); + if (subscriptionInfoList == null) { + return null; + } + + return subscriptionInfoList.get(slotId); + } + + @VisibleForTesting + String getCdmaPrlVersion() { + return mTelephonyManager.getCdmaPrlVersion(); + } + + @VisibleForTesting + boolean isCdmaLteEnabled() { + return mTelephonyManager.getLteOnCdmaMode(mSubscriptionInfo.getSubscriptionId()) + == PhoneConstants.LTE_ON_CDMA_TRUE; + } + + @VisibleForTesting + String getMeid() { + return mTelephonyManager.getMeid(mSlotId); + } +} diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogFragment.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogFragment.java new file mode 100644 index 00000000000..11e66f1c722 --- /dev/null +++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogFragment.java @@ -0,0 +1,94 @@ +/* + * 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.imei; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.Fragment; +import android.app.FragmentManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +public class ImeiInfoDialogFragment extends InstrumentedDialogFragment { + + @VisibleForTesting + static final String TAG = "ImeiInfoDialog"; + + private static final String SLOT_ID_BUNDLE_KEY = "arg_key_slot_id"; + private static final String DIALOG_TITLE_BUNDLE_KEY = "arg_key_dialog_title"; + + private View mRootView; + + public static void show(@NonNull Fragment host, int slotId, String dialogTitle) { + final FragmentManager manager = host.getChildFragmentManager(); + if (manager.findFragmentByTag(TAG) == null) { + final Bundle bundle = new Bundle(); + bundle.putInt(SLOT_ID_BUNDLE_KEY, slotId); + bundle.putString(DIALOG_TITLE_BUNDLE_KEY, dialogTitle); + final ImeiInfoDialogFragment dialog = new ImeiInfoDialogFragment(); + dialog.setArguments(bundle); + dialog.show(manager, TAG); + } + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.DIALOG_IMEI_INFO; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle bundle = getArguments(); + final int slotId = bundle.getInt(SLOT_ID_BUNDLE_KEY); + final String dialogTitle = bundle.getString(DIALOG_TITLE_BUNDLE_KEY); + + final ImeiInfoDialogController controller = new ImeiInfoDialogController(this, slotId); + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(dialogTitle) + .setPositiveButton(android.R.string.ok, null); + mRootView = LayoutInflater.from(builder.getContext()) + .inflate(R.layout.dialog_imei_info, null /* parent */); + controller.populateImeiInfo(); + return builder.setView(mRootView).create(); + } + + public void removeViewFromScreen(int viewId) { + final View view = mRootView.findViewById(viewId); + if (view != null) { + view.setVisibility(View.GONE); + } + } + + public void setText(int viewId, CharSequence text) { + final TextView textView = mRootView.findViewById(viewId); + if (TextUtils.isEmpty(text)) { + text = getResources().getString(R.string.device_info_default); + } + if (textView != null) { + textView.setText(text); + } + } +} diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceController.java new file mode 100644 index 00000000000..61d99b966f0 --- /dev/null +++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceController.java @@ -0,0 +1,57 @@ +/* + * 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.imei; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class ImeiInfoDualSimPreferenceController extends AbstractImeiInfoPreferenceController { + + private static final String KEY_IMEI_INFO_DUAL_SIM = "imei_info_sim_slot_2"; + private static final int SIM_SLOT = 1; + + public ImeiInfoDualSimPreferenceController(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public boolean isAvailable() { + return super.isAvailable() && mIsMultiSim; + } + + @Override + public String getPreferenceKey() { + return KEY_IMEI_INFO_DUAL_SIM; + } + + @Override + protected String getTitleForCdmaPhone() { + return mContext.getResources().getString(R.string.meid_multi_sim_sim_slot_2); + } + + @Override + protected String getTitleForGsmPhone() { + return mContext.getResources().getString(R.string.imei_multi_sim_slot_2); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } +} diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2.java new file mode 100644 index 00000000000..74448bb123e --- /dev/null +++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2.java @@ -0,0 +1,55 @@ +/* + * 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.imei; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class ImeiInfoPreferenceControllerV2 extends AbstractImeiInfoPreferenceController { + + public static final int SIM_SLOT = 0; + + private static final String KEY_IMEI_INFO = "imei_info_sim_slot_1"; + + public ImeiInfoPreferenceControllerV2(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public String getPreferenceKey() { + return KEY_IMEI_INFO; + } + + @Override + protected String getTitleForCdmaPhone() { + return mIsMultiSim ? mContext.getResources().getString(R.string.meid_multi_sim_sim_slot_1) + : mContext.getResources().getString(R.string.status_meid_number); + } + + @Override + protected String getTitleForGsmPhone() { + return mIsMultiSim ? mContext.getResources().getString(R.string.imei_multi_sim_slot_1) + : mContext.getResources().getString(R.string.status_imei); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceControllerTest.java new file mode 100644 index 00000000000..51e6005d743 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/AbstractImeiInfoPreferenceControllerTest.java @@ -0,0 +1,143 @@ +/* + * 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.imei; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; +import static android.telephony.TelephonyManager.PHONE_TYPE_GSM; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AbstractImeiInfoPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private AbstractImeiInfoPreferenceControllerImpl mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new AbstractImeiInfoPreferenceControllerImpl(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void displayPreference_cdmaPhone_shouldSetCdmaTitleAndMeid() { + mController = spy(mController); + final String meid = "125132215123"; + when(mTelephonyManager.getPhoneType()).thenReturn(PHONE_TYPE_CDMA); + doReturn(meid).when(mController).getMeid(); + + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(mController.getTitleForCdmaPhone()); + verify(mPreference).setSummary(meid); + } + + @Test + public void displayPreference_gsmPhone_shouldSetGsmTitleAndImei() { + final String imei = "125132215123"; + when(mTelephonyManager.getPhoneType()).thenReturn(PHONE_TYPE_GSM); + when(mTelephonyManager.getImei(anyInt())).thenReturn(imei); + + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(mController.getTitleForGsmPhone()); + verify(mPreference).setSummary(imei); + } + + @Test + public void handlePreferenceTreeClick_shouldStartDialogFragment() { + when(mFragment.getChildFragmentManager()).thenReturn( + mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS)); + when(mPreference.getTitle()).thenReturn("SomeTitle"); + mController.displayPreference(mScreen); + + mController.handlePreferenceTreeClick(mPreference); + + verify(mFragment).getChildFragmentManager(); + } + + public class AbstractImeiInfoPreferenceControllerImpl extends + AbstractImeiInfoPreferenceController { + + public AbstractImeiInfoPreferenceControllerImpl(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public String getPreferenceKey() { + return "foobar"; + } + + @Override + protected String getTitleForCdmaPhone() { + return "foo"; + } + + @Override + protected String getTitleForGsmPhone() { + return "bar"; + } + + @Override + protected int getSimSlot() { + return 0; + } + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java new file mode 100644 index 00000000000..bb4933bcddc --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java @@ -0,0 +1,133 @@ +/* + * 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.imei; + +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_CDMA_SETTINGS; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_GSM_SETTINGS; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_ICC_ID_LABEL; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_ICC_ID_VALUE; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_IMEI_SV_VALUE; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_IMEI_VALUE; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_MEID_NUMBER_VALUE; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_MIN_NUMBER_VALUE; +import static com.android.settings.deviceinfo.imei.ImeiInfoDialogController.ID_PRL_VERSION_VALUE; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ImeiInfoDialogControllerTest { + + private static final String PRL_VERSION = "some_prl_version"; + private static final String MEID_NUMBER = "12871234124"; + private static final String IMEI_NUMBER = "2341982751254"; + private static final String MIN_NUMBER = "123417851315"; + private static final String ICCID_NUMBER = "3845672472"; + private static final String IMEI_SV_NUMBER = "12"; + + @Mock + private ImeiInfoDialogFragment mDialog; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionInfo mSubscriptionInfo; + + private Context mContext; + private ImeiInfoDialogController mController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + when(mDialog.getContext()).thenReturn(mContext); + mController = spy(new ImeiInfoDialogController(mDialog, 0 /* phone id */)); + ReflectionHelpers.setField(mController, "mSubscriptionInfo", mSubscriptionInfo); + + doReturn(PRL_VERSION).when(mController).getCdmaPrlVersion(); + doReturn(MEID_NUMBER).when(mController).getMeid(); + when(mTelephonyManager.getCdmaMin(anyInt())).thenReturn(MIN_NUMBER); + when(mSubscriptionInfo.getIccId()).thenReturn(ICCID_NUMBER); + when(mTelephonyManager.getDeviceSoftwareVersion(anyInt())).thenReturn(IMEI_SV_NUMBER); + when(mTelephonyManager.getImei(anyInt())).thenReturn(IMEI_NUMBER); + } + + @Test + public void populateImeiInfo_cdmaLteEnabled_shouldSetMeidAndImeiAndMin() { + doReturn(true).when(mController).isCdmaLteEnabled(); + when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA); + + mController.populateImeiInfo(); + + verify(mDialog).setText(ID_MEID_NUMBER_VALUE, MEID_NUMBER); + verify(mDialog).setText(ID_MIN_NUMBER_VALUE, MIN_NUMBER); + verify(mDialog).setText(ID_PRL_VERSION_VALUE, PRL_VERSION); + verify(mDialog).setText(ID_ICC_ID_VALUE, ICCID_NUMBER); + verify(mDialog).setText(eq(ID_IMEI_VALUE), any()); + verify(mDialog).setText(eq(ID_IMEI_SV_VALUE), any()); + } + + @Test + public void populateImeiInfo_cdmaLteDisabled_shouldSetMeidAndMinAndRemoveGsmSettings() { + doReturn(false).when(mController).isCdmaLteEnabled(); + when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA); + + mController.populateImeiInfo(); + + verify(mDialog).setText(ID_MEID_NUMBER_VALUE, MEID_NUMBER); + verify(mDialog).setText(ID_MIN_NUMBER_VALUE, MIN_NUMBER); + verify(mDialog).setText(ID_PRL_VERSION_VALUE, PRL_VERSION); + verify(mDialog).removeViewFromScreen(ID_GSM_SETTINGS); + verify(mDialog).removeViewFromScreen(ID_ICC_ID_VALUE); + verify(mDialog).removeViewFromScreen(ID_ICC_ID_LABEL); + } + + @Test + public void populateImeinfo_gsm_shouldSetImeiAndRemoveCdmaSettings() { + when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_GSM); + + mController.populateImeiInfo(); + + verify(mDialog).setText(eq(ID_IMEI_VALUE), any()); + verify(mDialog).setText(eq(ID_IMEI_SV_VALUE), any()); + verify(mDialog).removeViewFromScreen(ID_CDMA_SETTINGS); + verify(mDialog).removeViewFromScreen(ID_ICC_ID_VALUE); + verify(mDialog).removeViewFromScreen(ID_ICC_ID_LABEL); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceControllerTest.java new file mode 100644 index 00000000000..ce99ee4f718 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDualSimPreferenceControllerTest.java @@ -0,0 +1,89 @@ +/* + * 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.imei; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ImeiInfoDualSimPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private ImeiInfoDualSimPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new ImeiInfoDualSimPreferenceController(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void getTitleForCdmaPhone_shouldReturnCdmaMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getTitleForCdmaPhone()).isEqualTo(mContext.getResources().getString( + R.string.meid_multi_sim_sim_slot_2)); + } + + @Test + public void getTitleForGsmPhone_shouldReturnGsmMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getTitleForGsmPhone()).isEqualTo(mContext.getResources().getString( + R.string.imei_multi_sim_slot_2)); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2Test.java new file mode 100644 index 00000000000..233e27e77a4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerV2Test.java @@ -0,0 +1,105 @@ +/* + * 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.imei; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ImeiInfoPreferenceControllerV2Test { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private ImeiInfoPreferenceControllerV2 mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new ImeiInfoPreferenceControllerV2(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void getTitleForCdmaPhone_noMultiSim_shouldReturnCdmaNoMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + assertThat(mController.getTitleForCdmaPhone()).isEqualTo(mContext.getResources().getString( + R.string.status_meid_number)); + } + + @Test + public void getTitleForCdmaPhone_multiSim_shouldReturnCdmaMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getTitleForCdmaPhone()).isEqualTo(mContext.getResources().getString( + R.string.meid_multi_sim_sim_slot_1)); + } + + @Test + public void getTitleForGsmPhone_noMultiSim_shouldReturnGsmNoMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + assertThat(mController.getTitleForGsmPhone()).isEqualTo(mContext.getResources().getString( + R.string.status_imei)); + } + + @Test + public void getTitleForGsmPhone_multiSim_shouldReturnGsmMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getTitleForGsmPhone()).isEqualTo(mContext.getResources().getString( + R.string.imei_multi_sim_slot_1)); + } +} From f0b027f4ce6d78533b3d17048b2ba15079ad1f94 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Wed, 1 Nov 2017 14:37:49 -0700 Subject: [PATCH 02/13] Improve settings cold start latency. - Move view initialization from onViewCreated to onCreateView. This doesn't really improve anything, it simply aligns the code more with view's lifecycle management. - Move dashboard category init into background. The init contains logic invoking packageManager, which can be very expensive. - Remove any call to DashboardFeatureProvider from SummaryLoader, and delay the getCategory call until someone calls setListener(). - call updateCategory() from background thread. Test: rerun app launch test. Avg latency drops back to pre-suggestion-v2 level. Test: robotest Fixes: 68761512 Change-Id: I5ec85af08e7b610786e439bda93b3651f5975593 --- .../settings/dashboard/DashboardSummary.java | 24 +++--- .../settings/dashboard/SummaryLoader.java | 75 ++++++++++--------- .../settings/dashboard/SummaryLoaderTest.java | 27 ++++--- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java index b7c87150fc2..8f66b67f4d9 100644 --- a/src/com/android/settings/dashboard/DashboardSummary.java +++ b/src/com/android/settings/dashboard/DashboardSummary.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Handler; import android.service.settings.suggestions.Suggestion; import android.support.annotation.VisibleForTesting; +import android.support.annotation.WorkerThread; import android.support.v7.widget.LinearLayoutManager; import android.util.Log; import android.view.LayoutInflater; @@ -50,6 +51,7 @@ import com.android.settingslib.drawer.SettingsDrawerActivity.CategoryListener; import com.android.settingslib.drawer.Tile; import com.android.settingslib.suggestions.SuggestionList; import com.android.settingslib.suggestions.SuggestionParser; +import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; import java.util.List; @@ -181,12 +183,6 @@ public class DashboardSummary extends InstrumentedFragment } } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.dashboard, container, false); - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -198,9 +194,10 @@ public class DashboardSummary extends InstrumentedFragment } @Override - public void onViewCreated(View view, Bundle bundle) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { long startTime = System.currentTimeMillis(); - mDashboard = view.findViewById(R.id.dashboard_container); + final View root = inflater.inflate(R.layout.dashboard, container, false); + mDashboard = root.findViewById(R.id.dashboard_container); mLayoutManager = new LinearLayoutManager(getContext()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); if (bundle != null) { @@ -218,19 +215,19 @@ public class DashboardSummary extends InstrumentedFragment mSummaryLoader.setSummaryConsumer(mAdapter); ActionBarShadowController.attachToRecyclerView( getActivity().findViewById(R.id.search_bar_container), getLifecycle(), mDashboard); - + rebuildUI(); if (DEBUG_TIMING) { - Log.d(TAG, "onViewCreated took " + Log.d(TAG, "onCreateView took " + (System.currentTimeMillis() - startTime) + " ms"); } - rebuildUI(); + return root; } @VisibleForTesting void rebuildUI() { if (!mSuggestionFeatureProvider.isSuggestionEnabled(getContext())) { Log.d(TAG, "Suggestion v1 feature is disabled, skipping suggestion v1"); - updateCategory(); + ThreadUtils.postOnBackgroundThread(() -> updateCategory()); } else { new SuggestionLoader().execute(); // Set categories on their own if loading suggestions takes too long. @@ -340,11 +337,12 @@ public class DashboardSummary extends InstrumentedFragment } } + @WorkerThread void updateCategory() { final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory( CategoryKey.CATEGORY_HOMEPAGE); mSummaryLoader.updateSummaryToCache(category); - mAdapter.setCategory(category); + ThreadUtils.postOnMainThread(() -> mAdapter.setCategory(category)); } /** diff --git a/src/com/android/settings/dashboard/SummaryLoader.java b/src/com/android/settings/dashboard/SummaryLoader.java index 5816bba8237..fe55be802a9 100644 --- a/src/com/android/settings/dashboard/SummaryLoader.java +++ b/src/com/android/settings/dashboard/SummaryLoader.java @@ -60,23 +60,6 @@ public class SummaryLoader { private boolean mWorkerListening; private ArraySet mReceivers = new ArraySet<>(); - public SummaryLoader(Activity activity, List categories) { - mDashboardFeatureProvider = FeatureFactory.getFactory(activity) - .getDashboardFeatureProvider(activity); - mCategoryKey = null; - mWorkerThread = new HandlerThread("SummaryLoader", Process.THREAD_PRIORITY_BACKGROUND); - mWorkerThread.start(); - mWorker = new Worker(mWorkerThread.getLooper()); - mActivity = activity; - for (int i = 0; i < categories.size(); i++) { - List tiles = categories.get(i).tiles; - for (int j = 0; j < tiles.size(); j++) { - Tile tile = tiles.get(j); - mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget(); - } - } - } - public SummaryLoader(Activity activity, String categoryKey) { mDashboardFeatureProvider = FeatureFactory.getFactory(activity) .getDashboardFeatureProvider(activity); @@ -85,17 +68,6 @@ public class SummaryLoader { mWorkerThread.start(); mWorker = new Worker(mWorkerThread.getLooper()); mActivity = activity; - - final DashboardCategory category = - mDashboardFeatureProvider.getTilesForCategory(categoryKey); - if (category == null || category.tiles == null) { - return; - } - - List tiles = category.tiles; - for (Tile tile : tiles) { - mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget(); - } } public void release() { @@ -153,15 +125,32 @@ public class SummaryLoader { * Only call from the main thread. */ public void setListening(boolean listening) { - if (mListening == listening) return; + if (mListening == listening) { + return; + } mListening = listening; // Unregister listeners immediately. for (int i = 0; i < mReceivers.size(); i++) { mActivity.unregisterReceiver(mReceivers.valueAt(i)); } mReceivers.clear(); + mWorker.removeMessages(Worker.MSG_SET_LISTENING); - mWorker.obtainMessage(Worker.MSG_SET_LISTENING, listening ? 1 : 0, 0).sendToTarget(); + if (!listening) { + // Stop listen + mWorker.obtainMessage(Worker.MSG_SET_LISTENING, 0 /* listening */).sendToTarget(); + } else { + // Start listen + if (mSummaryProviderMap.isEmpty()) { + // Category not initialized yet, init before starting to listen + if (!mWorker.hasMessages(Worker.MSG_GET_CATEGORY_TILES_AND_SET_LISTENING)) { + mWorker.sendEmptyMessage(Worker.MSG_GET_CATEGORY_TILES_AND_SET_LISTENING); + } + } else { + // Category already initialized, start listening immediately + mWorker.obtainMessage(Worker.MSG_SET_LISTENING, 1 /* listening */).sendToTarget(); + } + } } private SummaryProvider getSummaryProvider(Tile tile) { @@ -236,9 +225,13 @@ public class SummaryLoader { } private synchronized void setListeningW(boolean listening) { - if (mWorkerListening == listening) return; + if (mWorkerListening == listening) { + return; + } mWorkerListening = listening; - if (DEBUG) Log.d(TAG, "Listening " + listening); + if (DEBUG) { + Log.d(TAG, "Listening " + listening); + } for (SummaryProvider p : mSummaryProviderMap.keySet()) { try { p.setListening(listening); @@ -271,7 +264,6 @@ public class SummaryLoader { } - public interface SummaryProvider { void setListening(boolean listening); } @@ -285,8 +277,9 @@ public class SummaryLoader { } private class Worker extends Handler { - private static final int MSG_GET_PROVIDER = 1; - private static final int MSG_SET_LISTENING = 2; + private static final int MSG_GET_CATEGORY_TILES_AND_SET_LISTENING = 1; + private static final int MSG_GET_PROVIDER = 2; + private static final int MSG_SET_LISTENING = 3; public Worker(Looper looper) { super(looper); @@ -295,6 +288,18 @@ public class SummaryLoader { @Override public void handleMessage(Message msg) { switch (msg.what) { + case MSG_GET_CATEGORY_TILES_AND_SET_LISTENING: + final DashboardCategory category = + mDashboardFeatureProvider.getTilesForCategory(mCategoryKey); + if (category == null || category.tiles == null) { + return; + } + final List tiles = category.tiles; + for (Tile tile : tiles) { + makeProviderW(tile); + } + setListeningW(true); + break; case MSG_GET_PROVIDER: Tile tile = (Tile) msg.obj; makeProviderW(tile); diff --git a/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java b/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java index 146be9c7acb..44b61398b23 100644 --- a/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/SummaryLoaderTest.java @@ -16,6 +16,10 @@ package com.android.settings.dashboard; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -23,6 +27,7 @@ import android.content.Intent; import com.android.settings.TestConfig; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; @@ -35,12 +40,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; -import java.util.ArrayList; -import java.util.List; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.when; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class SummaryLoaderTest { @@ -65,14 +64,14 @@ public class SummaryLoaderTest { mCallbackInvoked = false; final Activity activity = Robolectric.buildActivity(Activity.class).get(); - final List categories = new ArrayList<>(); - mSummaryLoader = new SummaryLoader(activity, categories); - mSummaryLoader.setSummaryConsumer(new SummaryLoader.SummaryConsumer() { - @Override - public void notifySummaryChanged(Tile tile) { - mCallbackInvoked = true; - } - }); + + mSummaryLoader = new SummaryLoader(activity, CategoryKey.CATEGORY_HOMEPAGE); + mSummaryLoader.setSummaryConsumer(tile -> mCallbackInvoked = true); + } + + @Test + public void newInstance_shouldNotLoadCategory() { + verifyZeroInteractions(mFeatureFactory.dashboardFeatureProvider); } @Test From 5a66ddbd6f399e5413bc058ce12cb1646e4e3903 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Wed, 1 Nov 2017 12:54:29 -0700 Subject: [PATCH 03/13] Add screen resource for Colors setting. - each preference fragment should have its own preference screen layout in order to show the title correctly. Adding the missing data for ColorModePreferenceFragment. Change-Id: I172429dc957f94351456d4bc829897a578d7dbf9 Fixes: 68763217 Test: make RunSettingsRoboTests --- res/xml/color_mode_settings.xml | 21 ++++++++++++++++ .../display/ColorModePreferenceFragment.java | 5 ++++ .../widget/RadioButtonPickerFragment.java | 3 +++ .../DefaultAppPickerFragmentTest.java | 5 ++++ .../ColorModePreferenceFragmentTest.java | 24 ++++++++++++++++--- .../widget/RadioButtonPickerFragmentTest.java | 5 ++++ 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 res/xml/color_mode_settings.xml diff --git a/res/xml/color_mode_settings.xml b/res/xml/color_mode_settings.xml new file mode 100644 index 00000000000..b7f58d2ea08 --- /dev/null +++ b/res/xml/color_mode_settings.xml @@ -0,0 +1,21 @@ + + + + diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java index 07cf82e7901..9f18fd8423b 100644 --- a/src/com/android/settings/display/ColorModePreferenceFragment.java +++ b/src/com/android/settings/display/ColorModePreferenceFragment.java @@ -44,6 +44,11 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { mController = new NightDisplayController(context); } + @Override + protected int getPreferenceScreenResId() { + return R.xml.color_mode_settings; + } + @Override protected List getCandidates() { Context c = getContext(); diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java index 7489a772c5c..c7689090959 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -82,6 +82,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr return view; } + @Override + protected abstract int getPreferenceScreenResId(); + @Override public void onRadioButtonClicked(RadioButtonPreference selected) { final String selectedKey = selected.getKey(); diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java index 3621edd3645..42a62254a0a 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java @@ -114,6 +114,11 @@ public class DefaultAppPickerFragmentTest { return 0; } + @Override + protected int getPreferenceScreenResId() { + return 0; + } + @Override protected List getCandidates() { return new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java index 9ee79ffe545..fb9bb9f490b 100644 --- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java @@ -16,11 +16,18 @@ package com.android.settings.display; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Bundle; + import com.android.internal.app.NightDisplayController; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowSystemProperties; @@ -111,20 +118,31 @@ public class ColorModePreferenceFragmentTest { @Test public void setKey_natural() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_NATURAL); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_NATURAL); } @Config(shadows = {SettingsShadowSystemProperties.class}) @Test public void setKey_boosted() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_BOOSTED); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_BOOSTED); } @Config(shadows = {SettingsShadowSystemProperties.class}) @Test public void setKey_saturated() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_SATURATED); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_SATURATED); } + + @Test + public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() { + doNothing().when(mFragment).addPreferencesFromResource(anyInt()); + doNothing().when(mFragment).updateCandidates(); + + mFragment.onCreatePreferences(Bundle.EMPTY, null /* rootKey */); + + verify(mFragment).addPreferencesFromResource(R.xml.color_mode_settings); + } + } diff --git a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java index 40d73eb327a..8ca68ae50b7 100644 --- a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java +++ b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java @@ -113,6 +113,11 @@ public class RadioButtonPickerFragmentTest { return 0; } + @Override + protected int getPreferenceScreenResId() { + return 0; + } + @Override protected List getCandidates() { return new ArrayList<>(); From 44ce407d006722d6a426edcb701b3ba96cce87d6 Mon Sep 17 00:00:00 2001 From: Maurice Lam Date: Tue, 31 Oct 2017 21:46:38 -0700 Subject: [PATCH 04/13] Add flag to not connect in WifiDialogActivity Add flag connect_for_caller, which if false will not connect to the Wi-Fi network on behalf of the caller. Test: cd tests/robotests && mma Bug: 34951731 Change-Id: Ie24a8ed1891aea1caec75a2de9a3d2bdb3dad8a7 --- .../settings/wifi/WifiDialogActivity.java | 38 +++++--- .../src/com/android/settings/TestConfig.java | 8 ++ .../testutils/shadow/ShadowWifiManager.java | 49 ++++++++++ .../settings/wifi/WifiDialogActivityTest.java | 97 +++++++++++++++++++ 4 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java create mode 100644 tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java index 4f9c7a634ae..e2e3d019cd1 100644 --- a/src/com/android/settings/wifi/WifiDialogActivity.java +++ b/src/com/android/settings/wifi/WifiDialogActivity.java @@ -22,7 +22,9 @@ import android.content.Intent; import android.net.NetworkInfo; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.ActionListener; import android.os.Bundle; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.android.settings.SetupWizardUtils; @@ -40,6 +42,15 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo private static final String KEY_ACCESS_POINT_STATE = "access_point_state"; private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; + /** + * Boolean extra indicating whether this activity should connect to an access point on the + * caller's behalf. If this is set to false, the caller should check + * {@link #KEY_WIFI_CONFIGURATION} in the result data and save that using + * {@link WifiManager#connect(WifiConfiguration, ActionListener)}. Default is true. + */ + @VisibleForTesting + static final String KEY_CONNECT_FOR_CALLER = "connect_for_caller"; + @Override protected void onCreate(Bundle savedInstanceState) { final Intent intent = getIntent(); @@ -55,7 +66,8 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo accessPoint = new AccessPoint(this, accessPointState); } - WifiDialog dialog = WifiDialog.createModal(this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT); + WifiDialog dialog = WifiDialog.createModal( + this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT); dialog.show(); dialog.setOnDismissListener(this); } @@ -102,17 +114,19 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo final AccessPoint accessPoint = dialog.getController().getAccessPoint(); final WifiManager wifiManager = getSystemService(WifiManager.class); - if (config == null) { - if (accessPoint != null && accessPoint.isSaved()) { - wifiManager.connect(accessPoint.getConfig(), null /* listener */); - } - } else { - wifiManager.save(config, null /* listener */); - if (accessPoint != null) { - // accessPoint is null for "Add network" - NetworkInfo networkInfo = accessPoint.getNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - wifiManager.connect(config, null /* listener */); + if (getIntent().getBooleanExtra(KEY_CONNECT_FOR_CALLER, true)) { + if (config == null) { + if (accessPoint != null && accessPoint.isSaved()) { + wifiManager.connect(accessPoint.getConfig(), null /* listener */); + } + } else { + wifiManager.save(config, null /* listener */); + if (accessPoint != null) { + // accessPoint is null for "Add network" + NetworkInfo networkInfo = accessPoint.getNetworkInfo(); + if (networkInfo == null || !networkInfo.isConnected()) { + wifiManager.connect(config, null /* listener */); + } } } } diff --git a/tests/robotests/src/com/android/settings/TestConfig.java b/tests/robotests/src/com/android/settings/TestConfig.java index 3b2d2e46d42..d2d65a95ffa 100644 --- a/tests/robotests/src/com/android/settings/TestConfig.java +++ b/tests/robotests/src/com/android/settings/TestConfig.java @@ -16,10 +16,18 @@ package com.android.settings; +import android.os.Build; + /** * Constants for Robolectric config */ public class TestConfig { + + /** + * @deprecated New tests should use {@link #SDK_VERSION_O} + */ + @Deprecated public static final int SDK_VERSION = 23; + public static final int SDK_VERSION_O = Build.VERSION_CODES.O; public static final String MANIFEST_PATH = "packages/apps/Settings/AndroidManifest.xml"; } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java new file mode 100644 index 00000000000..e5304daf1bf --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java @@ -0,0 +1,49 @@ +/* + * 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.testutils.shadow; + +import static org.robolectric.RuntimeEnvironment.application; + +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; + +import org.robolectric.annotation.HiddenApi; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadow.api.Shadow; + +@Implements(WifiManager.class) +public class ShadowWifiManager extends org.robolectric.shadows.ShadowWifiManager { + + public WifiConfiguration savedWifiConfig; + + @HiddenApi // @SystemApi + @Implementation + public void connect(WifiConfiguration config, WifiManager.ActionListener listener) { + savedWifiConfig = config; + } + + @HiddenApi + @Implementation + public void save(WifiConfiguration config, WifiManager.ActionListener listener) { + savedWifiConfig = config; + } + + public static ShadowWifiManager get() { + return Shadow.extract(application.getSystemService(WifiManager.class)); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java new file mode 100644 index 00000000000..40c147862c4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; + +import android.content.Intent; +import android.net.wifi.WifiConfiguration; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.testutils.shadow.ShadowConnectivityManager; +import com.android.settings.testutils.shadow.ShadowWifiManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowAlertDialog; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config( + manifest = TestConfig.MANIFEST_PATH, + sdk = TestConfig.SDK_VERSION_O, + shadows = { + SettingsShadowResources.class, + SettingsShadowResources.SettingsShadowTheme.class, + ShadowConnectivityManager.class, + ShadowWifiManager.class + } +) +public class WifiDialogActivityTest { + + public static final String AP1_SSID = "\"ap1\""; + @Mock + private WifiConfigController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + WifiConfiguration wifiConfig = new WifiConfiguration(); + wifiConfig.SSID = AP1_SSID; + doReturn(wifiConfig).when(mController).getConfig(); + } + + @Test + public void onSubmit_shouldConnectToNetwork() { + WifiDialogActivity activity = Robolectric.setupActivity(WifiDialogActivity.class); + WifiDialog dialog = (WifiDialog) ShadowAlertDialog.getLatestAlertDialog(); + assertThat(dialog).isNotNull(); + + ReflectionHelpers.setField(dialog, "mController", mController); + + activity.onSubmit(dialog); + + assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP1_SSID); + } + + @Test + public void onSubmit_shouldNotConnectToNetwork_whenConnectForCallerIsFalse() { + WifiDialogActivity activity = + Robolectric.buildActivity( + WifiDialogActivity.class, + new Intent().putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false)) + .setup().get(); + WifiDialog dialog = (WifiDialog) ShadowAlertDialog.getLatestAlertDialog(); + assertThat(dialog).isNotNull(); + + ReflectionHelpers.setField(dialog, "mController", mController); + + activity.onSubmit(dialog); + + assertThat(ShadowWifiManager.get().savedWifiConfig).isNull(); + } +} From 7d7e98a214d6ea287e7b7c7b5fc96d5e52f16295 Mon Sep 17 00:00:00 2001 From: jeffreyhuang Date: Fri, 27 Oct 2017 14:41:56 -0700 Subject: [PATCH 05/13] Popup a dialog to display sim status information - Create layout files for the dialog - Create a new controller to launch the dialog activity - Create a new controller to update the contents of the dialog - Deprecate old files that are no longer used in about phone v2 Bug: 36458278 Test: make RunSettingsRoboTests -j40 Change-Id: Iaf4f5e53c83b27f148acb076f38bfeabff41087e --- res/layout/dialog_sim_status.xml | 132 ++++++ res/values/strings.xml | 8 + res/values/styles.xml | 10 + res/xml/device_info_settings_v2.xml | 11 +- .../android/settings/DeviceInfoSettings.java | 6 +- .../settings/deviceinfo/SimStatus.java | 2 + .../SimStatusPreferenceController.java | 5 + ...AbstractSimStatusPreferenceController.java | 98 +++++ .../simstatus/SimStatusDialogController.java | 375 ++++++++++++++++++ .../simstatus/SimStatusDialogFragment.java | 92 +++++ .../SimStatusDualSimPreferenceController.java | 52 +++ .../SimStatusPreferenceControllerV2.java | 49 +++ ...ractSimStatusPreferenceControllerTest.java | 113 ++++++ .../SimStatusDialogControllerTest.java | 202 ++++++++++ ...StatusDualSimPreferenceControllerTest.java | 93 +++++ .../SimStatusPreferenceControllerV2Test.java | 89 +++++ 16 files changed, 1334 insertions(+), 3 deletions(-) create mode 100644 res/layout/dialog_sim_status.xml create mode 100644 src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java create mode 100644 src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java create mode 100644 src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java create mode 100644 src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml new file mode 100644 index 00000000000..068a889def4 --- /dev/null +++ b/res/layout/dialog_sim_status.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index f0721fc7dcd..87abec52b22 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2671,6 +2671,10 @@ MDN Phone number + + MDN on SIM + + Phone number on SIM MIN @@ -6430,6 +6434,10 @@ No SIM cards inserted SIM status + + SIM status (sim slot 1) + + SIM status (sim slot 2) Call back from default SIM diff --git a/res/values/styles.xml b/res/values/styles.xml index c9ef22cfb97..8815bb3c762 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -478,4 +478,14 @@ @dimen/search_bar_text_size + + + + diff --git a/res/xml/device_info_settings_v2.xml b/res/xml/device_info_settings_v2.xml index 0553f1ebc5c..037db63c94b 100644 --- a/res/xml/device_info_settings_v2.xml +++ b/res/xml/device_info_settings_v2.xml @@ -28,12 +28,19 @@ android:title="@string/status_number" android:summary="@string/summary_placeholder"/> - + + + + + 1; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + if (mPreference == null) { + return; + } + + mPreference.setTitle(getPreferenceTitle()); + mPreference.setSummary(getCarrierName()); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + + SimStatusDialogFragment.show(mFragment, getSimSlot(), getPreferenceTitle()); + return true; + } + + /** + * @return The preference title for the displayed preference. + */ + protected abstract String getPreferenceTitle(); + + /** + * @return The sim slot to retrieve sim status information about. + */ + protected abstract int getSimSlot(); + + private CharSequence getCarrierName() { + final List subscriptionInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfoList != null) { + for (SubscriptionInfo info : subscriptionInfoList) { + if (info.getSimSlotIndex() == getSimSlot()) { + return info.getCarrierName(); + } + } + } + return mContext.getText(R.string.device_info_not_available); + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java new file mode 100644 index 00000000000..a6cc28f1857 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java @@ -0,0 +1,375 @@ +/* + * 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.simstatus; + +import static android.content.Context.TELEPHONY_SERVICE; + +import android.Manifest; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.UserHandle; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.telephony.CellBroadcastMessage; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.settings.R; +import com.android.settingslib.DeviceInfoUtils; +import com.android.settingslib.core.lifecycle.Lifecycle; +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.util.List; + +public class SimStatusDialogController implements LifecycleObserver, OnResume, OnPause { + + private final static String TAG = "SimStatusDialogCtrl"; + + @VisibleForTesting + final static int NETWORK_PROVIDER_VALUE_ID = R.id.operator_name_value; + @VisibleForTesting + final static int PHONE_NUMBER_VALUE_ID = R.id.number_value; + @VisibleForTesting + final static int CELLULAR_NETWORK_STATE = R.id.data_state_value; + @VisibleForTesting + final static int OPERATOR_INFO_LABEL_ID = R.id.latest_area_info_label; + @VisibleForTesting + final static int OPERATOR_INFO_VALUE_ID = R.id.latest_area_info_value; + @VisibleForTesting + final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value; + @VisibleForTesting + final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value; + @VisibleForTesting + final static int CELLULAR_NETWORK_TYPE_VALUE_ID = R.id.network_type_value; + @VisibleForTesting + final static int ROAMING_INFO_VALUE_ID = R.id.roaming_state_value; + + private final static String CB_AREA_INFO_RECEIVED_ACTION = + "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED"; + private final static String GET_LATEST_CB_AREA_INFO_ACTION = + "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO"; + private final static String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver"; + + private final SimStatusDialogFragment mDialog; + private final SubscriptionInfo mSubscriptionInfo; + private final TelephonyManager mTelephonyManager; + private final Resources mRes; + private final Context mContext; + + private boolean mShowLatestAreaInfo; + + private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (TextUtils.equals(action, CB_AREA_INFO_RECEIVED_ACTION)) { + final Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + final CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message"); + if (cbMessage != null + && mSubscriptionInfo.getSubscriptionId() == cbMessage.getSubId()) { + final String latestAreaInfo = cbMessage.getMessageBody(); + mDialog.setText(OPERATOR_INFO_VALUE_ID, latestAreaInfo); + } + } + } + }; + + + private PhoneStateListener mPhoneStateListener; + + public SimStatusDialogController(@NonNull SimStatusDialogFragment dialog, Lifecycle lifecycle, + int slotId) { + mDialog = dialog; + mContext = dialog.getContext(); + mSubscriptionInfo = getPhoneSubscriptionInfo(slotId); + mTelephonyManager = (TelephonyManager) mContext.getSystemService( + TELEPHONY_SERVICE); + mRes = mContext.getResources(); + + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + public void initialize() { + if (mSubscriptionInfo == null) { + return; + } + + mPhoneStateListener = getPhoneStateListener(); + + final ServiceState serviceState = getCurrentServiceState(); + updateNetworkProvider(serviceState); + updatePhoneNumber(); + updateLatestAreaInfo(); + updateServiceState(serviceState); + updateSignalStrength(getSignalStrength()); + updateNetworkType(); + updateRoamingStatus(serviceState); + } + + @Override + public void onResume() { + if (mSubscriptionInfo == null) { + return; + } + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS + | PhoneStateListener.LISTEN_SERVICE_STATE); + + if (mShowLatestAreaInfo) { + mContext.registerReceiver(mAreaInfoReceiver, + new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION), + Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null /* scheduler */); + // Ask CellBroadcastReceiver to broadcast the latest area info received + final Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION); + getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP); + mContext.sendBroadcastAsUser(getLatestIntent, UserHandle.ALL, + Manifest.permission.RECEIVE_EMERGENCY_BROADCAST); + } + } + + @Override + public void onPause() { + if (mSubscriptionInfo == null) { + return; + } + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_NONE); + + if (mShowLatestAreaInfo) { + mContext.unregisterReceiver(mAreaInfoReceiver); + } + } + + private void updateNetworkProvider(ServiceState serviceState) { + mDialog.setText(NETWORK_PROVIDER_VALUE_ID, serviceState.getOperatorAlphaLong()); + } + + private void updatePhoneNumber() { + // If formattedNumber is null or empty, it'll display as "Unknown". + mDialog.setText(PHONE_NUMBER_VALUE_ID, getPhoneNumber()); + } + + private void updateDataState(int state) { + String networkStateValue; + + switch (state) { + case TelephonyManager.DATA_CONNECTED: + networkStateValue = mRes.getString(R.string.radioInfo_data_connected); + break; + case TelephonyManager.DATA_SUSPENDED: + networkStateValue = mRes.getString(R.string.radioInfo_data_suspended); + break; + case TelephonyManager.DATA_CONNECTING: + networkStateValue = mRes.getString(R.string.radioInfo_data_connecting); + break; + case TelephonyManager.DATA_DISCONNECTED: + networkStateValue = mRes.getString(R.string.radioInfo_data_disconnected); + break; + default: + networkStateValue = mRes.getString(R.string.radioInfo_unknown); + break; + } + + mDialog.setText(CELLULAR_NETWORK_STATE, networkStateValue); + } + + + private void updateLatestAreaInfo() { + mShowLatestAreaInfo = Resources.getSystem().getBoolean( + com.android.internal.R.bool.config_showAreaUpdateInfoSettings) + && mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA; + + if (!mShowLatestAreaInfo) { + mDialog.removeSettingFromScreen(OPERATOR_INFO_LABEL_ID); + mDialog.removeSettingFromScreen(OPERATOR_INFO_VALUE_ID); + } + } + + private void updateServiceState(ServiceState serviceState) { + final int state = serviceState.getState(); + if (state == ServiceState.STATE_OUT_OF_SERVICE || state == ServiceState.STATE_POWER_OFF) { + resetSignalStrength(); + } + + String serviceStateValue; + + switch (state) { + case ServiceState.STATE_IN_SERVICE: + serviceStateValue = mRes.getString(R.string.radioInfo_service_in); + break; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + // Set summary string of service state to radioInfo_service_out when + // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY + serviceStateValue = mRes.getString(R.string.radioInfo_service_out); + break; + case ServiceState.STATE_POWER_OFF: + serviceStateValue = mRes.getString(R.string.radioInfo_service_off); + break; + default: + serviceStateValue = mRes.getString(R.string.radioInfo_unknown); + break; + } + + mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue); + } + + private void updateSignalStrength(SignalStrength signalStrength) { + final int state = getCurrentServiceState().getState(); + + if ((ServiceState.STATE_OUT_OF_SERVICE == state) || + (ServiceState.STATE_POWER_OFF == state)) { + return; + } + + int signalDbm = getDbm(signalStrength); + int signalAsu = getAsuLevel(signalStrength); + + if (signalDbm == -1) { + signalDbm = 0; + } + + if (signalAsu == -1) { + signalAsu = 0; + } + + mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength, + signalDbm, signalAsu)); + } + + private void resetSignalStrength() { + mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0"); + } + + private void updateNetworkType() { + // Whether EDGE, UMTS, etc... + String networktype = null; + final int subId = mSubscriptionInfo.getSubscriptionId(); + final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(subId); + final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(subId); + if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) { + networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType); + } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) { + networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType); + } + + boolean show4GForLTE = false; + try { + final Context con = mContext.createPackageContext( + "com.android.systemui", 0 /* flags */); + final int id = con.getResources().getIdentifier("config_show4GForLTE", + "bool" /* default type */, "com.android.systemui" /* default package */); + show4GForLTE = con.getResources().getBoolean(id); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "NameNotFoundException for show4GFotLTE"); + } + + if (TextUtils.equals(networktype, "LTE") && show4GForLTE) { + networktype = "4G"; + } + mDialog.setText(CELLULAR_NETWORK_TYPE_VALUE_ID, networktype); + } + + private void updateRoamingStatus(ServiceState serviceState) { + if (serviceState.getRoaming()) { + mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_in)); + } else { + mDialog.setText(ROAMING_INFO_VALUE_ID, mRes.getString(R.string.radioInfo_roaming_not)); + } + } + + private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) { + final List subscriptionInfoList = SubscriptionManager.from( + mContext).getActiveSubscriptionInfoList(); + if (subscriptionInfoList != null && subscriptionInfoList.size() > slotId) { + return subscriptionInfoList.get(slotId); + } else { + return null; + } + } + + @VisibleForTesting + ServiceState getCurrentServiceState() { + return mTelephonyManager.getServiceStateForSubscriber( + mSubscriptionInfo.getSubscriptionId()); + } + + @VisibleForTesting + int getDbm(SignalStrength signalStrength) { + return signalStrength.getDbm(); + } + + @VisibleForTesting + int getAsuLevel(SignalStrength signalStrength) { + return signalStrength.getAsuLevel(); + } + + @VisibleForTesting + PhoneStateListener getPhoneStateListener() { + return new PhoneStateListener( + mSubscriptionInfo.getSubscriptionId()) { + @Override + public void onDataConnectionStateChanged(int state) { + updateDataState(state); + updateNetworkType(); + } + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + updateSignalStrength(signalStrength); + } + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + updateNetworkProvider(serviceState); + updateServiceState(serviceState); + updateRoamingStatus(serviceState); + } + }; + } + + @VisibleForTesting + String getPhoneNumber() { + return DeviceInfoUtils.getFormattedPhoneNumber(mContext, mSubscriptionInfo); + } + + @VisibleForTesting + SignalStrength getSignalStrength() { + return mTelephonyManager.getSignalStrength(); + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java new file mode 100644 index 00000000000..a15cb81e011 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java @@ -0,0 +1,92 @@ +/* + * 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.simstatus; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.Fragment; +import android.app.FragmentManager; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +public class SimStatusDialogFragment extends InstrumentedDialogFragment { + + private static final String SIM_SLOT_BUNDLE_KEY = "arg_key_sim_slot"; + private static final String DIALOG_TITLE_BUNDLE_KEY = "arg_key_dialog_title"; + + private static final String TAG = "SimStatusDialog"; + + private View mRootView; + private SimStatusDialogController mController; + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.DIALOG_SIM_STATUS; + } + + public static void show(Fragment host, int slotId, String dialogTitle) { + final FragmentManager manager = host.getChildFragmentManager(); + if (manager.findFragmentByTag(TAG) == null) { + final Bundle bundle = new Bundle(); + bundle.putInt(SIM_SLOT_BUNDLE_KEY, slotId); + bundle.putString(DIALOG_TITLE_BUNDLE_KEY, dialogTitle); + final SimStatusDialogFragment dialog = + new SimStatusDialogFragment(); + dialog.setArguments(bundle); + dialog.show(manager, TAG); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle bundle = getArguments(); + final int slotId = bundle.getInt(SIM_SLOT_BUNDLE_KEY); + final String dialogTitle = bundle.getString(DIALOG_TITLE_BUNDLE_KEY); + mController = new SimStatusDialogController(this, mLifecycle, slotId); + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(dialogTitle) + .setPositiveButton(android.R.string.ok, null /* onClickListener */); + mRootView = LayoutInflater.from(builder.getContext()) + .inflate(R.layout.dialog_sim_status, null /* parent */); + mController.initialize(); + return builder.setView(mRootView).create(); + } + + public void removeSettingFromScreen(int viewId) { + final View view = mRootView.findViewById(viewId); + if (view != null) { + view.setVisibility(View.GONE); + } + } + + public void setText(int viewId, CharSequence text) { + final TextView textView = mRootView.findViewById(viewId); + if (TextUtils.isEmpty(text)) { + text = getResources().getString(R.string.device_info_default); + } + if (textView != null) { + textView.setText(text); + } + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java new file mode 100644 index 00000000000..ce73a294247 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceController.java @@ -0,0 +1,52 @@ +/* + * 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.simstatus; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class SimStatusDualSimPreferenceController extends AbstractSimStatusPreferenceController { + + private static final int SIM_SLOT = 1; + private static final String SIM_STATUS_DUAL_SIM_KEY = "sim_status_sim_2"; + + public SimStatusDualSimPreferenceController(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public boolean isAvailable() { + return super.isAvailable() && mIsMultiSim; + } + + @Override + protected String getPreferenceTitle() { + return mContext.getResources().getString(R.string.sim_status_title_sim_slot_2); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } + + @Override + public String getPreferenceKey() { + return SIM_STATUS_DUAL_SIM_KEY; + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java new file mode 100644 index 00000000000..ee16eac5bf3 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2.java @@ -0,0 +1,49 @@ +/* + * 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.simstatus; + +import android.app.Fragment; +import android.content.Context; + +import com.android.settings.R; + +public class SimStatusPreferenceControllerV2 extends AbstractSimStatusPreferenceController { + + public static final int SIM_SLOT = 0; + + private static final String KEY_SIM_1_STATUS = "sim_status_sim_1"; + + public SimStatusPreferenceControllerV2(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + protected String getPreferenceTitle() { + return mIsMultiSim ? mContext.getResources().getString(R.string.sim_status_title_sim_slot_1) + : mContext.getResources().getString(R.string.sim_status_title); + } + + @Override + protected int getSimSlot() { + return SIM_SLOT; + } + + @Override + public String getPreferenceKey() { + return KEY_SIM_1_STATUS; + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java new file mode 100644 index 00000000000..ee749d085d3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/AbstractSimStatusPreferenceControllerTest.java @@ -0,0 +1,113 @@ +/* + * 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.simstatus; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AbstractSimStatusPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private AbstractSimStatusPreferenceControllerImpl mController; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new AbstractSimStatusPreferenceControllerImpl(mContext, mFragment); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void displayPreference_shouldSetTitleAndSummary() { + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(mController.getPreferenceTitle()); + verify(mPreference).setSummary(anyString()); + } + + @Test + public void handlePreferenceTreeClick_shouldStartDialogFragment() { + when(mFragment.getChildFragmentManager()).thenReturn( + mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS)); + when(mPreference.getTitle()).thenReturn("foo"); + mController.displayPreference(mScreen); + + mController.handlePreferenceTreeClick(mPreference); + + verify(mFragment).getChildFragmentManager(); + } + + public class AbstractSimStatusPreferenceControllerImpl extends + AbstractSimStatusPreferenceController { + + public AbstractSimStatusPreferenceControllerImpl(Context context, Fragment fragment) { + super(context, fragment); + } + + @Override + public String getPreferenceKey() { + return "foo"; + } + + @Override + protected String getPreferenceTitle() { + return "bar"; + } + + @Override + protected int getSimSlot() { + return 0; + } + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java new file mode 100644 index 00000000000..73db81d9327 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -0,0 +1,202 @@ +/* + * 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.simstatus; + +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .CELLULAR_NETWORK_TYPE_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .NETWORK_PROVIDER_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .OPERATOR_INFO_LABEL_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .OPERATOR_INFO_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .PHONE_NUMBER_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .ROAMING_INFO_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .SERVICE_STATE_VALUE_ID; +import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController + .SIGNAL_STRENGTH_VALUE_ID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusDialogControllerTest { + + @Mock + private SimStatusDialogFragment mDialog; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionInfo mSubscriptionInfo; + @Mock + private ServiceState mServiceState; + @Mock + private PhoneStateListener mPhoneStateListener; + @Mock + private SignalStrength mSignalStrength; + + + private SimStatusDialogController mController; + private Context mContext; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + when(mDialog.getContext()).thenReturn(mContext); + mController = spy( + new SimStatusDialogController(mDialog, new Lifecycle(), 0 /* phone id */)); + doReturn(mServiceState).when(mController).getCurrentServiceState(); + doReturn(0).when(mController).getDbm(any()); + doReturn(0).when(mController).getAsuLevel(any()); + doReturn(mPhoneStateListener).when(mController).getPhoneStateListener(); + doReturn("").when(mController).getPhoneNumber(); + doReturn(mSignalStrength).when(mController).getSignalStrength(); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + ReflectionHelpers.setField(mController, "mSubscriptionInfo", mSubscriptionInfo); + } + + @Test + public void initialize_updateNetworkProviderWithFoobarCarrier_shouldUpdateCarrierWithFoobar() { + final String carrierName = "foobar"; + when(mServiceState.getOperatorAlphaLong()).thenReturn(carrierName); + + mController.initialize(); + + verify(mDialog).setText(NETWORK_PROVIDER_VALUE_ID, carrierName); + } + + @Test + public void initialize_updatePhoneNumberWith1111111111_shouldUpdatePhoneNumber() { + final String phoneNumber = "1111111111"; + doReturn(phoneNumber).when(mController).getPhoneNumber(); + + mController.initialize(); + + verify(mDialog).setText(PHONE_NUMBER_VALUE_ID, phoneNumber); + } + + @Test + public void initialize_updateLatestAreaInfoWithCdmaPhone_shouldRemoveOperatorInfoSetting() { + when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA); + + mController.initialize(); + + verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_LABEL_ID); + verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_VALUE_ID); + } + + @Test + public void initialize_updateServiceStateWithInService_shouldUpdateTextToBeCInService() { + when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE); + + mController.initialize(); + + final String inServiceText = mContext.getResources().getString( + R.string.radioInfo_service_in); + verify(mDialog).setText(SERVICE_STATE_VALUE_ID, inServiceText); + } + + @Test + public void initialize_updateDataStateWithPowerOff_shouldUpdateSettingAndResetSignalStrength() { + when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF); + + mController.initialize(); + + final String offServiceText = mContext.getResources().getString( + R.string.radioInfo_service_off); + verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText); + verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0"); + } + + @Test + public void initialize_updateSignalStrengthWith50_shouldUpdateSignalStrengthTo50() { + final int signalDbm = 50; + final int signalAsu = 50; + doReturn(signalDbm).when(mController).getDbm(mSignalStrength); + doReturn(signalAsu).when(mController).getAsuLevel(mSignalStrength); + + mController.initialize(); + + final String signalStrengthString = mContext.getResources().getString( + R.string.sim_signal_strength, signalDbm, signalAsu); + verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString); + } + + @Test + public void initialize_updateNetworkTypeWithEdge_shouldUpdateSettingToEdge() { + when(mTelephonyManager.getDataNetworkType(anyInt())).thenReturn( + TelephonyManager.NETWORK_TYPE_EDGE); + + mController.initialize(); + + verify(mDialog).setText(CELLULAR_NETWORK_TYPE_VALUE_ID, + TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_EDGE)); + } + + @Test + public void initialize_updateRoamingStatusIsRoaming_shouldSetSettingToRoaming() { + when(mServiceState.getRoaming()).thenReturn(true); + + mController.initialize(); + + final String roamingOnString = mContext.getResources().getString( + R.string.radioInfo_roaming_in); + verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOnString); + } + + @Test + public void initialize_updateRoamingStatusNotRoaming_shouldSetSettingToRoamingOff() { + when(mServiceState.getRoaming()).thenReturn(false); + + mController.initialize(); + + final String roamingOffString = mContext.getResources().getString( + R.string.radioInfo_roaming_not); + verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOffString); + } + +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java new file mode 100644 index 00000000000..0845bfa95e9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDualSimPreferenceControllerTest.java @@ -0,0 +1,93 @@ +/* + * 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.simstatus; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.content.Context; +import android.net.ConnectivityManager; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import com.google.common.truth.Truth; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusDualSimPreferenceControllerTest { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private SimStatusDualSimPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + doReturn(mConnectivityManager).when(mContext).getSystemService(ConnectivityManager.class); + when(mUserManager.isAdminUser()).thenReturn(true); + when(mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn( + true); + mController = new SimStatusDualSimPreferenceController(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void isAvailable_multiSim_shouldBeTrue() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + Truth.assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_notMultiSim_shouldBeFalse() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + Truth.assertThat(mController.isAvailable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java new file mode 100644 index 00000000000..3282c3c85f7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerV2Test.java @@ -0,0 +1,89 @@ +/* + * 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.simstatus; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Fragment; +import android.content.Context; +import android.os.UserManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.telephony.TelephonyManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SimStatusPreferenceControllerV2Test { + + @Mock + private Preference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private UserManager mUserManager; + @Mock + private Fragment mFragment; + + private Context mContext; + private SimStatusPreferenceControllerV2 mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); + mController = new SimStatusPreferenceControllerV2(mContext, mFragment); + ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + } + + @Test + public void getPreferenceTitle_noMultiSim_shouldReturnSingleSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", false); + + assertThat(mController.getPreferenceTitle()).isEqualTo(mContext.getResources().getString( + R.string.sim_status_title)); + } + + @Test + public void getPreferenceTitle_multiSim_shouldReturnMultiSimString() { + ReflectionHelpers.setField(mController, "mIsMultiSim", true); + + assertThat(mController.getPreferenceTitle()).isEqualTo(mContext.getResources().getString( + R.string.sim_status_title_sim_slot_1)); + } +} From 1aefa2529a94bb16502a61c9d271f84bb138e9b1 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 10 Oct 2017 14:06:04 -0700 Subject: [PATCH 06/13] Set device credential's Window flag to be SECURE. This prevents showing any pattern/pin in recent list. Change-Id: I445cbad99344a2fcc335a5aad4a4de026ae97441 Merged-In: Ie56f725bf245961d61a66eae8a82b728600cb650 Fixes: 64339515 Bug: 38258991 Test: manual --- src/com/android/settings/ConfirmLockPassword.java | 2 ++ src/com/android/settings/ConfirmLockPattern.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java index c74e8617b06..dac943d326e 100644 --- a/src/com/android/settings/ConfirmLockPassword.java +++ b/src/com/android/settings/ConfirmLockPassword.java @@ -38,6 +38,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.TextView; @@ -72,6 +73,7 @@ public class ConfirmLockPassword extends SettingsActivity { super.onCreate(savedInstanceState); CharSequence msg = getText(R.string.lockpassword_confirm_your_password_header); setTitle(msg); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } public static class ConfirmLockPasswordFragment extends Fragment implements OnClickListener, diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java index caf691d0b01..be88e9858ad 100644 --- a/src/com/android/settings/ConfirmLockPattern.java +++ b/src/com/android/settings/ConfirmLockPattern.java @@ -32,6 +32,7 @@ import android.widget.TextView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import java.util.List; @@ -69,6 +70,7 @@ public class ConfirmLockPattern extends SettingsActivity { super.onCreate(savedInstanceState); CharSequence msg = getText(R.string.lockpassword_confirm_your_pattern_header); setTitle(msg); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } @Override From c58a88368f109a362f40881a4a0589a31650749f Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Wed, 1 Nov 2017 17:59:53 -0700 Subject: [PATCH 07/13] Convert encryption status to preference controller - Move Crypt/Encryption setting into security package. - Reformat crypt_keeper_settings.xml - Add controller and test for encryption status Bug: 32953042 Test: robotests Change-Id: I1f4b2f97133435c70a49522a59886ac4da6759af --- AndroidManifest.xml | 2 +- res/layout/crypt_keeper_settings.xml | 37 +++----- res/xml/encryption_and_credential.xml | 79 ++++++++++------ res/xml/security_settings_encrypted.xml | 33 ------- res/xml/security_settings_unencrypted.xml | 32 ------- .../applications/DefaultAppSettings.java | 4 +- .../core/gateway/SettingsGateway.java | 6 +- .../{ => security}/CryptKeeperSettings.java | 5 +- .../security/EncryptionAndCredential.java | 80 +++++------------ .../EncryptionStatusPreferenceController.java | 61 +++++++++++++ ...java => PreferenceCategoryController.java} | 9 +- .../security/EncryptionAndCredentialTest.java | 41 --------- ...ryptionStatusPreferenceControllerTest.java | 90 +++++++++++++++++++ .../shadow/ShadowLockPatternUtils.java | 11 +++ ... => PreferenceCategoryControllerTest.java} | 6 +- 15 files changed, 268 insertions(+), 228 deletions(-) delete mode 100644 res/xml/security_settings_encrypted.xml delete mode 100644 res/xml/security_settings_unencrypted.xml rename src/com/android/settings/{ => security}/CryptKeeperSettings.java (98%) create mode 100644 src/com/android/settings/security/EncryptionStatusPreferenceController.java rename src/com/android/settings/widget/{WorkOnlyCategoryPreferenceController.java => PreferenceCategoryController.java} (82%) create mode 100644 tests/robotests/src/com/android/settings/security/EncryptionStatusPreferenceControllerTest.java rename tests/robotests/src/com/android/settings/widget/{WorkOnlyCategoryPreferenceControllerTest.java => PreferenceCategoryControllerTest.java} (91%) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5a310e980f3..16baf544f81 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2384,7 +2384,7 @@ + android:value="com.android.settings.security.CryptKeeperSettings" /> - - + android:paddingStart="@dimen/preference_no_icon_padding_start" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:orientation="vertical"> + android:layout_weight="1"> + android:orientation="vertical"> + android:text="@string/crypt_keeper_desc" /> + android:visibility="gone" /> + android:visibility="gone" /> -