diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2c3e7f3d12a..185d21ec7b2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2397,6 +2397,7 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index 57a96f98806..bd4e0186b3c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -131,7 +131,7 @@ Hearing device settings - Audio output, shortcut, hearing aid compatibility + Shortcut, hearing aid compatibility For this device @@ -2648,6 +2648,8 @@ Model Hardware version + + Manufactured year Equipment ID diff --git a/res/xml/hardware_info.xml b/res/xml/hardware_info.xml index 641f707a65e..e086a486ee0 100644 --- a/res/xml/hardware_info.xml +++ b/res/xml/hardware_info.xml @@ -48,4 +48,13 @@ settings:controller="com.android.settings.deviceinfo.hardwareinfo.HardwareRevisionPreferenceController" settings:enableCopying="true"/> + + + diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 1d45c518a6f..c43bde64a35 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -66,6 +66,7 @@ import android.text.TextUtils.TruncateAt; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -155,12 +156,12 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mHandler = new Handler(getMainLooper()); - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); + mDPM = getSystemService(DevicePolicyManager.class); + mAppOps = getSystemService(AppOpsManager.class); mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); PackageManager packageManager = getPackageManager(); - if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task"); finish(); return; @@ -170,7 +171,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { EXTRA_CALLED_FROM_SUPPORT_DIALOG, false); String action = getIntent().getAction(); - ComponentName who = (ComponentName)getIntent().getParcelableExtra( + ComponentName who = (ComponentName) getIntent().getParcelableExtra( DevicePolicyManager.EXTRA_DEVICE_ADMIN); if (who == null) { String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME); @@ -226,7 +227,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); int count = avail == null ? 0 : avail.size(); boolean found = false; - for (int i=0; i getString(R.string.device_admin_warning_simplified, - profileOwnerName), profileOwnerName)); + profileOwnerName), profileOwnerName)); return; } setContentView(R.layout.device_admin_add); - mAdminIcon = (ImageView)findViewById(R.id.admin_icon); - mAdminName = (TextView)findViewById(R.id.admin_name); - mAdminDescription = (TextView)findViewById(R.id.admin_description); + mAdminIcon = (ImageView) findViewById(R.id.admin_icon); + mAdminName = (TextView) findViewById(R.id.admin_name); + mAdminDescription = (TextView) findViewById(R.id.admin_description); mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning); mProfileOwnerWarning.setText( mDPM.getResources().getString(SET_PROFILE_OWNER_POSTSETUP_WARNING, () -> getString(R.string.adding_profile_owner_warning))); - mAddMsg = (TextView)findViewById(R.id.add_msg); + mAddMsg = (TextView) findViewById(R.id.add_msg); mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander); final View.OnClickListener onClickListener = new View.OnClickListener() { @Override @@ -380,7 +381,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines; mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE); if (hideMsgExpander) { - ((View)mAddMsgExpander.getParent()).invalidate(); + ((View) mAddMsgExpander.getParent()).invalidate(); } mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this); } @@ -398,7 +399,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mCancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER, - mDeviceAdmin.getActivityInfo().applicationInfo.uid); + mDeviceAdmin.getActivityInfo().applicationInfo.uid); finish(); } }); @@ -420,58 +421,64 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { final View restrictedAction = findViewById(R.id.restricted_action); restrictedAction.setFilterTouchesWhenObscured(true); - restrictedAction.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - if (!mActionButton.isEnabled()) { - showPolicyTransparencyDialogIfRequired(); - return; - } - if (mAdding) { - addAndFinish(); - } else if (isManagedProfile(mDeviceAdmin) - && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { - final int userId = UserHandle.myUserId(); - UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - UserManager um = UserManager.get(DeviceAdminAdd.this); - um.removeUser(userId); - finish(); - } - } - ).show(); - } else if (mUninstalling) { - mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); - finish(); - } else if (!mWaitingForRemoveMsg) { - try { - // Don't allow the admin to put a dialog up in front - // of us while we interact with the user. - ActivityManager.getService().stopAppSwitches(); - } catch (RemoteException e) { - } - mWaitingForRemoveMsg = true; - mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), - new RemoteCallback(new RemoteCallback.OnResultListener() { - @Override - public void onResult(Bundle result) { - CharSequence msg = result != null - ? result.getCharSequence( - DeviceAdminReceiver.EXTRA_DISABLE_WARNING) - : null; - continueRemoveAction(msg); - } - }, mHandler)); - // Don't want to wait too long. - getWindow().getDecorView().getHandler().postDelayed(new Runnable() { - @Override public void run() { - continueRemoveAction(null); - } - }, 2*1000); - } + + final View.OnClickListener restrictedActionClickListener = v -> { + if (!mActionButton.isEnabled()) { + showPolicyTransparencyDialogIfRequired(); + return; } + if (mAdding) { + addAndFinish(); + } else if (isManagedProfile(mDeviceAdmin) + && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) { + final int userId = UserHandle.myUserId(); + UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + UserManager um = UserManager.get(DeviceAdminAdd.this); + um.removeUser(userId); + finish(); + } + } + ).show(); + } else if (mUninstalling) { + mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName()); + finish(); + } else if (!mWaitingForRemoveMsg) { + try { + // Don't allow the admin to put a dialog up in front + // of us while we interact with the user. + ActivityManager.getService().stopAppSwitches(); + } catch (RemoteException e) { + } + mWaitingForRemoveMsg = true; + mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), + new RemoteCallback(new RemoteCallback.OnResultListener() { + @Override + public void onResult(Bundle result) { + CharSequence msg = result != null + ? result.getCharSequence( + DeviceAdminReceiver.EXTRA_DISABLE_WARNING) + : null; + continueRemoveAction(msg); + } + }, mHandler)); + // Don't want to wait too long. + getWindow().getDecorView().getHandler().postDelayed( + () -> continueRemoveAction(null), 2 * 1000); + } + }; + restrictedAction.setOnKeyListener((view, keyCode, keyEvent) -> { + if ((keyEvent.getFlags() & KeyEvent.FLAG_FROM_SYSTEM) == 0) { + Log.e(TAG, "Can not activate device-admin with KeyEvent from non-system app."); + // Consume event to suppress click. + return true; + } + // Fallback to view click handler. + return false; }); + restrictedAction.setOnClickListener(restrictedActionClickListener); } /** diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index bff998a4a3e..bea0c3389ec 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -120,6 +120,8 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { protected void onCreate(Bundle savedInstanceState) { mFaceManager = getFaceManager(); + super.onCreate(savedInstanceState); + if (savedInstanceState == null && !WizardManagerHelper.isAnySetupWizard(getIntent()) && !getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false) @@ -130,8 +132,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { finish(); } - super.onCreate(savedInstanceState); - // Wait super::onCreated() then return because SuperNotCalledExceptio will be thrown // if we don't wait for it. if (isFinishing()) { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintAuthenticateSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintAuthenticateSidecar.java index 426405627ab..f3c8aba4095 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintAuthenticateSidecar.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintAuthenticateSidecar.java @@ -21,6 +21,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.os.CancellationSignal; +import com.android.internal.annotations.VisibleForTesting; import com.android.settings.core.InstrumentedFragment; /** @@ -80,7 +81,6 @@ public class FingerprintAuthenticateSidecar extends InstrumentedFragment { @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { - mCancellationSignal = null; if (mListener != null) { mListener.onAuthenticationError(errMsgId, errString); } else { @@ -108,10 +108,12 @@ public class FingerprintAuthenticateSidecar extends InstrumentedFragment { } public void stopAuthentication() { - if (mCancellationSignal != null && !mCancellationSignal.isCanceled()) { + if (mCancellationSignal != null) { + // This will automatically check if the cancel has been sent and if so + // it won't send it again. mCancellationSignal.cancel(); + mCancellationSignal = null; } - mCancellationSignal = null; } public void setListener(Listener listener) { @@ -129,4 +131,9 @@ public class FingerprintAuthenticateSidecar extends InstrumentedFragment { } mListener = listener; } + + @VisibleForTesting + boolean isCancelled() { + return mCancellationSignal == null || mCancellationSignal.isCanceled(); + } } \ No newline at end of file diff --git a/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceController.java b/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceController.java index 8ad2ecab894..7d10b5b8a7f 100644 --- a/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceController.java +++ b/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceController.java @@ -17,32 +17,51 @@ package com.android.settings.deviceinfo.batteryinfo; import android.content.Context; +import android.os.BatteryManager; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.overlay.FeatureFactory; +import java.util.concurrent.TimeUnit; + /** * A controller that manages the information about battery first use date. */ public class BatteryFirstUseDatePreferenceController extends BasePreferenceController { - private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; + private final BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; + private final BatteryManager mBatteryManager; + + private long mFirstUseDateInMs; public BatteryFirstUseDatePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mBatterySettingsFeatureProvider = FeatureFactory.getFactory( - context).getBatterySettingsFeatureProvider(context); + context).getBatterySettingsFeatureProvider(); + mBatteryManager = mContext.getSystemService(BatteryManager.class); } @Override public int getAvailabilityStatus() { - return mBatterySettingsFeatureProvider.isFirstUseDateAvailable() + return mBatterySettingsFeatureProvider.isFirstUseDateAvailable(getFirstUseDate()) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override public CharSequence getSummary() { - return mBatterySettingsFeatureProvider.getFirstUseDateSummary(); + return isAvailable() + ? BatteryUtils.getBatteryInfoFormattedDate(mFirstUseDateInMs) + : null; + } + + private long getFirstUseDate() { + if (mFirstUseDateInMs == 0L) { + final long firstUseDateInSec = mBatteryManager.getLongProperty( + BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE); + mFirstUseDateInMs = TimeUnit.MILLISECONDS.convert(firstUseDateInSec, TimeUnit.SECONDS); + } + return mFirstUseDateInMs; } } diff --git a/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceController.java b/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceController.java index 45b299ab5a7..d1b9df03a82 100644 --- a/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceController.java +++ b/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceController.java @@ -17,32 +17,52 @@ package com.android.settings.deviceinfo.batteryinfo; import android.content.Context; +import android.os.BatteryManager; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.overlay.FeatureFactory; +import java.util.concurrent.TimeUnit; + /** * A controller that manages the information about battery manufacture date. */ public class BatteryManufactureDatePreferenceController extends BasePreferenceController { - private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; + private final BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; + private final BatteryManager mBatteryManager; + + private long mManufactureDateInMs; public BatteryManufactureDatePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mBatterySettingsFeatureProvider = FeatureFactory.getFactory( - context).getBatterySettingsFeatureProvider(context); + context).getBatterySettingsFeatureProvider(); + mBatteryManager = mContext.getSystemService(BatteryManager.class); } @Override public int getAvailabilityStatus() { - return mBatterySettingsFeatureProvider.isManufactureDateAvailable() + return mBatterySettingsFeatureProvider.isManufactureDateAvailable(getManufactureDate()) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override public CharSequence getSummary() { - return mBatterySettingsFeatureProvider.getManufactureDateSummary(); + return isAvailable() + ? BatteryUtils.getBatteryInfoFormattedDate(mManufactureDateInMs) + : null; + } + + private long getManufactureDate() { + if (mManufactureDateInMs == 0L) { + final long manufactureDateInSec = mBatteryManager.getLongProperty( + BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE); + mManufactureDateInMs = TimeUnit.MILLISECONDS.convert(manufactureDateInSec, + TimeUnit.SECONDS); + } + return mManufactureDateInMs; } } diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProvider.kt b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProvider.kt new file mode 100644 index 00000000000..400ece9a217 --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProvider.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.deviceinfo.hardwareinfo + +/** + * Feature provider for hardware info + */ +interface HardwareInfoFeatureProvider { + /** + * Returns the manufactured year + */ + val manufacturedYear: String? +} \ No newline at end of file diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProviderImpl.kt b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProviderImpl.kt new file mode 100644 index 00000000000..54a112bec35 --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareInfoFeatureProviderImpl.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.deviceinfo.hardwareinfo + +/** + * Feature provider for hardware info + */ +object HardwareInfoFeatureProviderImpl : HardwareInfoFeatureProvider { + override val manufacturedYear: String? + get() = null +} \ No newline at end of file diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/ManufacturedYearPreferenceController.kt b/src/com/android/settings/deviceinfo/hardwareinfo/ManufacturedYearPreferenceController.kt new file mode 100644 index 00000000000..0b0eeb750ec --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/ManufacturedYearPreferenceController.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.deviceinfo.hardwareinfo + +import android.content.Context +import com.android.settings.core.BasePreferenceController +import com.android.settings.overlay.FeatureFactory + +/** Preference controller for Manufactured Year. */ +class ManufacturedYearPreferenceController(context: Context, preferenceKey: String) : + BasePreferenceController(context, preferenceKey) { + private val year: String? = + FeatureFactory.getFactory(context).hardwareInfoFeatureProvider.manufacturedYear + + override fun getAvailabilityStatus(): Int = + if (!year.isNullOrEmpty()) AVAILABLE else UNSUPPORTED_ON_DEVICE + + override fun getSummary(): CharSequence = year ?: "" +} \ No newline at end of file diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java index 18fef1a374f..dd13f1c4842 100644 --- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java @@ -20,15 +20,8 @@ package com.android.settings.fuelgauge; public interface BatterySettingsFeatureProvider { /** Returns true if manufacture date should be shown */ - boolean isManufactureDateAvailable(); + boolean isManufactureDateAvailable(long manufactureDateMs); /** Returns true if first use date should be shown */ - boolean isFirstUseDateAvailable(); - - /** Returns the summary of battery manufacture date */ - CharSequence getManufactureDateSummary(); - - /** Returns the summary of battery first use date */ - CharSequence getFirstUseDateSummary(); - + boolean isFirstUseDateAvailable(long firstUseDateMs); } diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java index ed4795ab785..2dcb1b12004 100644 --- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java @@ -16,77 +16,16 @@ package com.android.settings.fuelgauge; -import android.content.Context; -import android.os.BatteryManager; - -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.concurrent.TimeUnit; - /** Feature provider implementation for battery settings usage. */ public class BatterySettingsFeatureProviderImpl implements BatterySettingsFeatureProvider { - protected Context mContext; - - private BatteryManager mBatteryManager; - private long mManufactureDateInMs; - private long mFirstUseDateInMs; - - public BatterySettingsFeatureProviderImpl(Context context) { - mContext = context.getApplicationContext(); - mBatteryManager = mContext.getSystemService(BatteryManager.class); - } - @Override - public boolean isManufactureDateAvailable() { + public boolean isManufactureDateAvailable(long manufactureDateMs) { return false; } @Override - public boolean isFirstUseDateAvailable() { + public boolean isFirstUseDateAvailable(long firstUseDateMs) { return false; } - - @Override - public CharSequence getManufactureDateSummary() { - return isManufactureDateAvailable() - ? getFormattedDate(getManufactureDate()) - : null; - } - - @Override - public CharSequence getFirstUseDateSummary() { - return isFirstUseDateAvailable() - ? getFormattedDate(getFirstUseDate()) - : null; - } - - protected long getManufactureDate() { - if (mManufactureDateInMs == 0L) { - final long manufactureDateInSec = mBatteryManager.getLongProperty( - BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE); - mManufactureDateInMs = TimeUnit.MILLISECONDS.convert(manufactureDateInSec, - TimeUnit.SECONDS); - } - return mManufactureDateInMs; - } - - protected long getFirstUseDate() { - if (mFirstUseDateInMs == 0L) { - final long firstUseDateInSec = mBatteryManager.getLongProperty( - BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE); - mFirstUseDateInMs = TimeUnit.MILLISECONDS.convert(firstUseDateInSec, TimeUnit.SECONDS); - } - return mFirstUseDateInMs; - } - - private CharSequence getFormattedDate(long dateInMs) { - final Instant instant = Instant.ofEpochMilli(dateInMs); - final String localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate().format( - DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)); - - return localDate; - } } diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index f5d3950fc2f..29c7591863c 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -64,8 +64,10 @@ import com.google.protobuf.MessageLite; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.time.Duration; import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.List; /** @@ -671,6 +673,14 @@ public class BatteryUtils { } return summary.toString(); } + /** Format the date of battery related info */ + public static CharSequence getBatteryInfoFormattedDate(long dateInMs) { + final Instant instant = Instant.ofEpochMilli(dateInMs); + final String localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate().format( + DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)); + + return localDate; + } /** Builds the battery usage time information for one timestamp. */ private static String buildBatteryUsageTimeInfo(final Context context, long timeInMs, diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java index 9d81baa9bca..249caa111fb 100644 --- a/src/com/android/settings/overlay/FeatureFactory.java +++ b/src/com/android/settings/overlay/FeatureFactory.java @@ -33,6 +33,7 @@ import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider; import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider; import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; import com.android.settings.fuelgauge.BatteryStatusFeatureProvider; @@ -110,6 +111,11 @@ public abstract class FeatureFactory { */ public abstract SuggestionFeatureProvider getSuggestionFeatureProvider(); + /** + * Retrieves implementation for Hardware Info feature. + */ + public abstract HardwareInfoFeatureProvider getHardwareInfoFeatureProvider(); + public abstract SupportFeatureProvider getSupportFeatureProvider(Context context); public abstract MetricsFeatureProvider getMetricsFeatureProvider(); @@ -125,8 +131,7 @@ public abstract class FeatureFactory { /** * Gets implementation for Battery Settings provider. */ - public abstract BatterySettingsFeatureProvider getBatterySettingsFeatureProvider( - Context context); + public abstract BatterySettingsFeatureProvider getBatterySettingsFeatureProvider(); public abstract DashboardFeatureProvider getDashboardFeatureProvider(Context context); diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java index d4f18782c05..60adf958545 100644 --- a/src/com/android/settings/overlay/FeatureFactoryImpl.java +++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java @@ -47,6 +47,8 @@ import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProviderImpl; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProviderImpl; import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; import com.android.settings.enterprise.EnterprisePrivacyFeatureProviderImpl; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; @@ -118,6 +120,11 @@ public class FeatureFactoryImpl extends FeatureFactory { private WifiFeatureProvider mWifiFeatureProvider; private KeyboardSettingsFeatureProvider mKeyboardSettingsFeatureProvider; + @Override + public HardwareInfoFeatureProvider getHardwareInfoFeatureProvider() { + return HardwareInfoFeatureProviderImpl.INSTANCE; + } + @Override public SupportFeatureProvider getSupportFeatureProvider(Context context) { return null; @@ -150,9 +157,9 @@ public class FeatureFactoryImpl extends FeatureFactory { } @Override - public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider(Context context) { + public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider() { if (mBatterySettingsFeatureProvider == null) { - mBatterySettingsFeatureProvider = new BatterySettingsFeatureProviderImpl(context); + mBatterySettingsFeatureProvider = new BatterySettingsFeatureProviderImpl(); } return mBatterySettingsFeatureProvider; } diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 216f7db1ac1..943a937a32a 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -71,6 +71,8 @@ public final class ChooseLockSettingsHelper { // Gatekeeper password handle, which can subsequently be used to generate Gatekeeper // HardwareAuthToken(s) via LockSettingsService#verifyGatekeeperPasswordHandle public static final String EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle"; + public static final String EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW = + "request_write_repair_mode_pw"; /** * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are @@ -152,6 +154,7 @@ public final class ChooseLockSettingsHelper { @Nullable private RemoteLockscreenValidationSession mRemoteLockscreenValidationSession; @Nullable private ComponentName mRemoteLockscreenValidationServiceComponent; private boolean mRequestGatekeeperPasswordHandle; + private boolean mRequestWriteRepairModePassword; private boolean mTaskOverlay; public Builder(@NonNull Activity activity) { @@ -335,6 +338,17 @@ public final class ChooseLockSettingsHelper { return this; } + /** + * @param requestWriteRepairModePassword Set {@code true} to request that + * LockSettingsService writes the password data to the repair mode file after the user + * credential is verified successfully. + */ + @NonNull public Builder setRequestWriteRepairModePassword( + boolean requestWriteRepairModePassword) { + mRequestWriteRepairModePassword = requestWriteRepairModePassword; + return this; + } + /** * Support of ActivityResultLauncher. * @@ -385,7 +399,7 @@ public final class ChooseLockSettingsHelper { mBuilder.mRemoteLockscreenValidationSession, mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle, - mBuilder.mTaskOverlay); + mBuilder.mRequestWriteRepairModePassword, mBuilder.mTaskOverlay); } private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @@ -396,7 +410,7 @@ public final class ChooseLockSettingsHelper { @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, @Nullable ComponentName remoteLockscreenValidationServiceComponent, boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, - boolean taskOverlay) { + boolean requestWriteRepairModePassword, boolean taskOverlay) { Optional> activityClass = determineAppropriateActivityClass( returnCredentials, forceVerifyPath, userId, remoteLockscreenValidationSession); if (activityClass.isEmpty()) { @@ -407,7 +421,7 @@ public final class ChooseLockSettingsHelper { returnCredentials, external, forceVerifyPath, userId, alternateButton, checkboxLabel, remoteLockscreenValidation, remoteLockscreenValidationSession, remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly, - requestGatekeeperPasswordHandle, taskOverlay); + requestGatekeeperPasswordHandle, requestWriteRepairModePassword, taskOverlay); } private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, @@ -418,7 +432,7 @@ public final class ChooseLockSettingsHelper { @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, @Nullable ComponentName remoteLockscreenValidationServiceComponent, boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, - boolean taskOverlay) { + boolean requestWriteRepairModePassword, boolean taskOverlay) { final Intent intent = new Intent(); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header); @@ -442,6 +456,8 @@ public final class ChooseLockSettingsHelper { intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, requestGatekeeperPasswordHandle); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, + requestWriteRepairModePassword); intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName()); intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE, diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index fabca6bb983..d409c0f9dfb 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -171,6 +171,9 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL.equals(intent.getAction()); mTaskOverlay = isInternalActivity() && intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false); + final boolean prepareRepairMode = + KeyguardManager.ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL.equals( + intent.getAction()); mUserId = UserHandle.myUserId(); if (isInternalActivity()) { @@ -244,6 +247,17 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { .setExternal(true) .show(); return; + } else if (prepareRepairMode) { + final ChooseLockSettingsHelper.Builder builder = + new ChooseLockSettingsHelper.Builder(this); + launchedCDC = builder.setHeader(mTitle) + .setDescription(mDetails) + .setExternal(true) + .setUserId(mUserId) + .setTaskOverlay(mTaskOverlay) + .setRequestWriteRepairModePassword(true) + .setForceVerifyPath(true) + .show(); } else if (isEffectiveUserManagedProfile && isInternalActivity()) { mCredentialMode = CREDENTIAL_MANAGED; if (isBiometricAllowed(effectiveUserId, mUserId)) { diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index f4cfabc754c..5a123b89315 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -105,6 +105,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr protected final Handler mHandler = new Handler(); protected boolean mFrp; protected boolean mRemoteValidation; + protected boolean mRequestWriteRepairModePassword; protected CharSequence mAlternateButtonText; protected BiometricManager mBiometricManager; @Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession; @@ -130,6 +131,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, false); mForceVerifyPath = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, false); + mRequestWriteRepairModePassword = intent.getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, false); if (intent.getBooleanExtra(IS_REMOTE_LOCKSCREEN_VALIDATION, false)) { if (FeatureFlagUtils.isEnabled(getContext(), diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 03b89f25051..1b535069f3c 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -496,7 +496,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { } } else if (mForceVerifyPath) { if (isInternalActivity()) { - startVerifyPassword(credential, intent, 0 /* flags */); + final int flags = mRequestWriteRepairModePassword + ? LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW : 0; + startVerifyPassword(credential, intent, flags); return; } } else { diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index e99a986ebe6..3951bde9bac 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -512,7 +512,9 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { } } else if (mForceVerifyPath) { if (isInternalActivity()) { - startVerifyPattern(credential, intent, 0 /* flags */); + final int flags = mRequestWriteRepairModePassword + ? LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW : 0; + startVerifyPattern(credential, intent, flags); return; } } else { diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java index c4da1335509..df15e5c32f8 100644 --- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java @@ -40,6 +40,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; import android.hardware.face.Face; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorProperties; @@ -116,6 +117,7 @@ public class FaceEnrollIntroductionTest { private FaceEnrollIntroduction mSpyActivity; private FakeFeatureFactory mFakeFeatureFactory; private ShadowUserManager mUserManager; + private Resources mResources; enum GateKeeperAction {CALL_SUPER, RETURN_BYTE_ARRAY, THROW_CREDENTIAL_NOT_MATCH} @@ -245,6 +247,14 @@ public class FaceEnrollIntroductionTest { when(mFaceManager.getEnrolledFaces(anyInt())).thenReturn(faces); } + private void setFaceManagerToHaveWithUserId(int numEnrollments, int userId) { + List faces = new ArrayList<>(); + for (int i = 0; i < numEnrollments; i++) { + faces.add(new Face("Face " + i /* name */, 1 /*faceId */, 1 /* deviceId */)); + } + when(mFaceManager.getEnrolledFaces(userId)).thenReturn(faces); + } + @Test public void intro_CheckCanEnroll() { setFaceManagerToHave(0 /* numEnrollments */); @@ -546,4 +556,40 @@ public class FaceEnrollIntroductionTest { assertThat(mActivity.getPostureCallback()).isNull(); } + @Test + public void testFaceEnrollIntroduction_maxFacesNotEnrolled_addUserProfile() { + // Enroll a face for one user + setFaceManagerToHaveWithUserId(1, 0); + + mContext = spy(ApplicationProvider.getApplicationContext()); + mResources = spy(mContext.getResources()); + when(mResources.getInteger(R.integer.suw_max_faces_enrollable)).thenReturn(1); + + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, new Intent()); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + + mController.create(); + + // The maximum number of faces is already enrolled + int result = mActivity.checkMaxEnrolled(); + assertThat(result).isEqualTo(R.string.face_intro_error_max); + + // Add another user profile + mUserManager.addUser(10, "", 0); + final Intent intent = new Intent(); + intent.putExtra(Intent.EXTRA_USER_ID, 10); + + when(mResources.getInteger(R.integer.suw_max_faces_enrollable)).thenReturn(2); + + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + + mController.create(); + + // The maximum number of faces hasn't been enrolled, so a new face + // can be enrolled for the added user profile + result = mActivity.checkMaxEnrolled(); + assertThat(result).isEqualTo(0); + } + } diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java index 18b05add7ad..1998d56b1ca 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java @@ -44,6 +44,7 @@ import android.hardware.biometrics.SensorProperties; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; +import android.os.CancellationSignal; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -68,6 +69,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -92,6 +94,16 @@ public class FingerprintSettingsFragmentTest { @Mock private FragmentTransaction mFragmentTransaction; + @Captor + private ArgumentCaptor mCancellationSignalArgumentCaptor = + ArgumentCaptor.forClass(CancellationSignal.class); + @Captor + private ArgumentCaptor + mAuthenticationCallbackArgumentCaptor = ArgumentCaptor.forClass( + FingerprintManager.AuthenticationCallback.class); + + private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar; + @Before public void setUp() { doReturn(true).when(mFingerprintManager).isHardwareDetected(); @@ -146,6 +158,34 @@ public class FingerprintSettingsFragmentTest { false)).isTrue(); } + // Test the case when FingerprintAuthenticateSidecar receives an error callback from the + // framework or from another authentication client. The cancellation signal should not be set + // to null because there may exist a running authentication client. + // The signal can only be cancelled from the caller in FingerprintSettings. + @Test + public void testCancellationSignalLifeCycle() { + setUpFragment(false); + + mFingerprintAuthenticateSidecar.setFingerprintManager(mFingerprintManager); + + doNothing().when(mFingerprintManager).authenticate(any(), + mCancellationSignalArgumentCaptor.capture(), + mAuthenticationCallbackArgumentCaptor.capture(), any(), anyInt()); + + mFingerprintAuthenticateSidecar.startAuthentication(1); + + assertThat(mAuthenticationCallbackArgumentCaptor.getValue()).isNotNull(); + assertThat(mCancellationSignalArgumentCaptor.getValue()).isNotNull(); + + // Authentication error callback should not cancel the signal. + mAuthenticationCallbackArgumentCaptor.getValue().onAuthenticationError(0, ""); + assertThat(mFingerprintAuthenticateSidecar.isCancelled()).isFalse(); + + // The signal should be cancelled when caller stops the authentication. + mFingerprintAuthenticateSidecar.stopAuthentication(); + assertThat(mFingerprintAuthenticateSidecar.isCancelled()).isTrue(); + } + private void setUpFragment(boolean showChooseLock) { Intent intent = new Intent(); if (!showChooseLock) { @@ -166,6 +206,10 @@ public class FingerprintSettingsFragmentTest { doReturn(fragmentManager).when(mFragment).getFragmentManager(); doReturn(fragmentManager).when(mActivity).getSupportFragmentManager(); + mFingerprintAuthenticateSidecar = new FingerprintAuthenticateSidecar(); + doReturn(mFingerprintAuthenticateSidecar).when(fragmentManager).findFragmentByTag( + "authenticate_sidecar"); + doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt()); setSensor(); diff --git a/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceControllerTest.java index a7f6a2e4a2b..9ac69af4462 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryFirstUseDatePreferenceControllerTest.java @@ -21,9 +21,12 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.content.Context; +import android.os.BatteryManager; import androidx.test.core.app.ApplicationProvider; @@ -33,16 +36,23 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowBatteryManager; @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBatteryManager.class}) public class BatteryFirstUseDatePreferenceControllerTest { private BatteryFirstUseDatePreferenceController mController; private Context mContext; + private BatteryManager mBatteryManager; + private ShadowBatteryManager mShadowBatteryManager; private FakeFeatureFactory mFactory; @Before public void setUp() { mContext = ApplicationProvider.getApplicationContext(); + mBatteryManager = mContext.getSystemService(BatteryManager.class); + mShadowBatteryManager = shadowOf(mBatteryManager); mFactory = FakeFeatureFactory.setupForTest(); mController = new BatteryFirstUseDatePreferenceController(mContext, "battery_info_first_use_date"); @@ -50,15 +60,37 @@ public class BatteryFirstUseDatePreferenceControllerTest { @Test public void getAvailabilityStatus_dateAvailable_returnAvailable() { - when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable()).thenReturn(true); + when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable(anyLong())) + .thenReturn(true); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test public void getAvailabilityStatus_dateUnavailable_returnNotAvailable() { - when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable()).thenReturn(false); + when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable(anyLong())) + .thenReturn(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } + + @Test + public void getSummary_available_returnExpectedDate() { + when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable(anyLong())) + .thenReturn(true); + mShadowBatteryManager.setLongProperty(BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE, + 1669680000L); + + final CharSequence result = mController.getSummary(); + + assertThat(result.toString()).isEqualTo("November 29, 2022"); + } + + @Test + public void getSummary_unavailable_returnNull() { + when(mFactory.batterySettingsFeatureProvider.isFirstUseDateAvailable(anyLong())) + .thenReturn(false); + + assertThat(mController.getSummary()).isNull(); + } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceControllerTest.java index c4a5486b259..fed74f3a8f9 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryManufactureDatePreferenceControllerTest.java @@ -21,9 +21,12 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.content.Context; +import android.os.BatteryManager; import androidx.test.core.app.ApplicationProvider; @@ -33,17 +36,24 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowBatteryManager; @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBatteryManager.class}) public class BatteryManufactureDatePreferenceControllerTest { private BatteryManufactureDatePreferenceController mController; private Context mContext; + private BatteryManager mBatteryManager; + private ShadowBatteryManager mShadowBatteryManager; private FakeFeatureFactory mFactory; @Before public void setUp() { mContext = ApplicationProvider.getApplicationContext(); + mBatteryManager = mContext.getSystemService(BatteryManager.class); + mShadowBatteryManager = shadowOf(mBatteryManager); mFactory = FakeFeatureFactory.setupForTest(); mController = new BatteryManufactureDatePreferenceController(mContext, "battery_info_manufacture_date"); @@ -51,16 +61,37 @@ public class BatteryManufactureDatePreferenceControllerTest { @Test public void getAvailabilityStatus_dateAvailable_returnAvailable() { - when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable()).thenReturn(true); + when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable( + anyLong())).thenReturn(true); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test public void getAvailabilityStatus_dateUnavailable_returnNotAvailable() { - when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable()) + when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable(anyLong())) .thenReturn(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } + + @Test + public void getSummary_available_returnExpectedDate() { + when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable( + anyLong())).thenReturn(true); + mShadowBatteryManager.setLongProperty(BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE, + 1669680000L); + + final CharSequence result = mController.getSummary(); + + assertThat(result.toString()).isEqualTo("November 29, 2022"); + } + + @Test + public void getSummary_unavailable_returnNull() { + when(mFactory.batterySettingsFeatureProvider.isManufactureDateAvailable(anyLong())) + .thenReturn(false); + + assertThat(mController.getSummary()).isNull(); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java index dfef3c7f0b8..6c0912561b2 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java @@ -18,83 +18,29 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.robolectric.Shadows.shadowOf; - -import android.content.Context; -import android.os.BatteryManager; - -import androidx.test.core.app.ApplicationProvider; +import static org.mockito.ArgumentMatchers.anyLong; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowBatteryManager; @RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowBatteryManager.class}) public class BatterySettingsFeatureProviderImplTest { - private BatteryManager mBatteryManager; - private ShadowBatteryManager mShadowBatteryManager; - private Context mContext; private BatterySettingsFeatureProviderImpl mImpl; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(ApplicationProvider.getApplicationContext()); - mBatteryManager = mContext.getSystemService(BatteryManager.class); - mShadowBatteryManager = shadowOf(mBatteryManager); - mImpl = spy(new BatterySettingsFeatureProviderImpl(mContext)); + mImpl = new BatterySettingsFeatureProviderImpl(); } @Test public void isManufactureDateAvailable_returnFalse() { - assertThat(mImpl.isManufactureDateAvailable()).isFalse(); + assertThat(mImpl.isManufactureDateAvailable(anyLong())).isFalse(); } @Test public void isFirstUseDateAvailable_returnFalse() { - assertThat(mImpl.isFirstUseDateAvailable()).isFalse(); - } - - @Test - public void getManufactureDateSummary_available_returnExpectedDate() { - doReturn(true).when(mImpl).isManufactureDateAvailable(); - mShadowBatteryManager.setLongProperty(BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE, - 1669680000L); - - final CharSequence result = mImpl.getManufactureDateSummary(); - - assertThat(result.toString()).isEqualTo("November 29, 2022"); - } - - @Test - public void getManufactureDateSummary_unavailable_returnNull() { - doReturn(false).when(mImpl).isManufactureDateAvailable(); - - assertThat(mImpl.getManufactureDateSummary()).isNull(); - } - - @Test - public void getFirstUseDateSummary_available_returnExpectedDate() { - doReturn(true).when(mImpl).isFirstUseDateAvailable(); - mShadowBatteryManager.setLongProperty(BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE, - 1669680000L); - - final CharSequence result = mImpl.getFirstUseDateSummary(); - - assertThat(result.toString()).isEqualTo("November 29, 2022"); - } - - @Test - public void getFirstUseDateSummary_unavailable_returnNull() { - doReturn(false).when(mImpl).isFirstUseDateAvailable(); - - assertThat(mImpl.getFirstUseDateSummary()).isNull(); + assertThat(mImpl.isFirstUseDateAvailable(anyLong())).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java index 47053802e39..fcb01b4649e 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -31,6 +31,8 @@ import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider; import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProviderImpl; import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; import com.android.settings.fuelgauge.BatteryStatusFeatureProvider; @@ -171,7 +173,7 @@ public class FakeFeatureFactory extends FeatureFactory { } @Override - public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider(Context context) { + public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider() { return batterySettingsFeatureProvider; } @@ -290,6 +292,11 @@ public class FakeFeatureFactory extends FeatureFactory { return mAccessibilityMetricsFeatureProvider; } + @Override + public HardwareInfoFeatureProvider getHardwareInfoFeatureProvider() { + return HardwareInfoFeatureProviderImpl.INSTANCE; + } + @Override public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() { return mAdvancedVpnFeatureProvider; diff --git a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt index 50589ac67e0..68078f8ba56 100644 --- a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt +++ b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt @@ -27,6 +27,7 @@ import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider import com.android.settings.bluetooth.BluetoothFeatureProvider import com.android.settings.dashboard.DashboardFeatureProvider import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider import com.android.settings.fuelgauge.BatterySettingsFeatureProvider import com.android.settings.fuelgauge.BatteryStatusFeatureProvider @@ -84,9 +85,7 @@ class FakeFeatureFactory : FeatureFactory() { TODO("Not yet implemented") } - override fun getBatterySettingsFeatureProvider( - context: Context?, - ): BatterySettingsFeatureProvider { + override fun getBatterySettingsFeatureProvider(): BatterySettingsFeatureProvider { TODO("Not yet implemented") } @@ -176,6 +175,10 @@ class FakeFeatureFactory : FeatureFactory() { TODO("Not yet implemented") } + override fun getHardwareInfoFeatureProvider(): HardwareInfoFeatureProvider { + TODO("Not yet implemented") + } + override fun getAdvancedVpnFeatureProvider(): AdvancedVpnFeatureProvider { TODO("Not yet implemented") } diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java index d7490100990..7a498652a5d 100644 --- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -29,6 +29,8 @@ import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider; import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider; +import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProviderImpl; import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider; import com.android.settings.fuelgauge.BatterySettingsFeatureProvider; import com.android.settings.fuelgauge.BatteryStatusFeatureProvider; @@ -157,7 +159,7 @@ public class FakeFeatureFactory extends FeatureFactory { } @Override - public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider(Context context) { + public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider() { return batterySettingsFeatureProvider; } @@ -276,6 +278,11 @@ public class FakeFeatureFactory extends FeatureFactory { return mAccessibilityMetricsFeatureProvider; } + @Override + public HardwareInfoFeatureProvider getHardwareInfoFeatureProvider() { + return HardwareInfoFeatureProviderImpl.INSTANCE; + } + @Override public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() { return mAdvancedVpnFeatureProvider;