Merge "Fix following three issues in SD Card UX" into tm-qpr-dev
diff --git a/src/com/android/settings/accessibility/AccessibilityStatsLogUtils.java b/src/com/android/settings/accessibility/AccessibilityStatsLogUtils.java
index d8a887d..e78982a 100644
--- a/src/com/android/settings/accessibility/AccessibilityStatsLogUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityStatsLogUtils.java
@@ -28,6 +28,7 @@
import android.content.ComponentName;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.settings.core.instrumentation.SettingsStatsLog;
/** Methods for logging accessibility states. */
@@ -112,4 +113,26 @@
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_UNKNOWN_ENTRY;
}
}
+
+ /**
+ * Converts the entering page id where the hearing aid binding process starts for logging.
+ *
+ * @param pageId the entry page id where the hearing aid binding process starts
+ * @return the int value for logging mapped from some page ids defined in
+ * {@link SettingsStatsLog}
+ */
+ public static int convertToHearingAidInfoBondEntry(int pageId) {
+ switch (pageId) {
+ case SettingsStatsLog.SETTINGS_UICHANGED__PAGE_ID__SETTINGS_CONNECTED_DEVICE_CATEGORY:
+ return FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__CONNECTED_DEVICES;
+ case SettingsStatsLog.SETTINGS_UICHANGED__PAGE_ID__DIALOG_ACCESSIBILITY_HEARINGAID:
+ return FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__ACCESSIBILITY_HEARING_AIDS;
+ case SettingsStatsLog.SETTINGS_UICHANGED__PAGE_ID__DIALOG_ACCESSIBILITY_HEARING_AID_PAIR_ANOTHER:
+ return FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__ACCESSIBILITY_HEARING_AID_PAIR_ANOTHER;
+ case SettingsStatsLog.SETTINGS_UICHANGED__PAGE_ID__BLUETOOTH_FRAGMENT:
+ return FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH;
+ default:
+ return FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__PAGE_UNKNOWN;
+ }
+ }
}
diff --git a/src/com/android/settings/accessibility/HearingAidDialogFragment.java b/src/com/android/settings/accessibility/HearingAidDialogFragment.java
index 107c56d..7f3230f 100644
--- a/src/com/android/settings/accessibility/HearingAidDialogFragment.java
+++ b/src/com/android/settings/accessibility/HearingAidDialogFragment.java
@@ -51,7 +51,7 @@
private void launchBluetoothAddDeviceSetting() {
new SubSettingLauncher(getActivity())
.setDestination(BluetoothPairingDetail.class.getName())
- .setSourceMetricsCategory(SettingsEnums.ACCESSIBILITY)
+ .setSourceMetricsCategory(getMetricsCategory())
.launch();
}
}
diff --git a/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java b/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java
index 3674212..c0f96c8 100644
--- a/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java
+++ b/src/com/android/settings/applications/AppStateAppBatteryUsageBridge.java
@@ -22,6 +22,7 @@
import android.os.Build;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
@@ -37,14 +38,21 @@
private static final String TAG = AppStateAppBatteryUsageBridge.class.getSimpleName();
static final boolean DEBUG = Build.IS_DEBUGGABLE;
- private final Context mContext;
- private final AppOpsManager mAppOpsManager;
- private final PowerAllowlistBackend mPowerAllowlistBackend;
+ @VisibleForTesting
+ Context mContext;
+ @VisibleForTesting
+ AppOpsManager mAppOpsManager;
+ @VisibleForTesting
+ PowerAllowlistBackend mPowerAllowlistBackend;
- private static final int MODE_UNKNOWN = 0;
- private static final int MODE_UNRESTRICTED = 1;
- private static final int MODE_OPTIMIZED = 2;
- private static final int MODE_RESTRICTED = 3;
+ @VisibleForTesting
+ static final int MODE_UNKNOWN = 0;
+ @VisibleForTesting
+ static final int MODE_UNRESTRICTED = 1;
+ @VisibleForTesting
+ static final int MODE_OPTIMIZED = 2;
+ @VisibleForTesting
+ static final int MODE_RESTRICTED = 3;
@IntDef(
prefix = {"MODE_"},
@@ -110,8 +118,9 @@
return new AppBatteryUsageDetails(mode);
}
+ @VisibleForTesting
@OptimizationMode
- private static int getAppBatteryUsageDetailsMode(AppEntry entry) {
+ static int getAppBatteryUsageDetailsMode(AppEntry entry) {
if (entry == null || entry.extraInfo == null) {
return MODE_UNKNOWN;
}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 018fda5..9a4d13c 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -1196,9 +1196,12 @@
rebuild(R.id.sort_order_alpha, true);
}
return;
- } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+ }
+
+ if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
logAppBatteryUsage(filterType);
}
+
rebuild();
}
@@ -1673,7 +1676,7 @@
holder.setSummary(AppLocaleDetails.getSummary(mContext, entry));
break;
case LIST_TYPE_BATTERY_OPTIMIZATION:
- holder.setSummary(R.string.app_battery_usage_summary);
+ holder.setSummary(null);
break;
default:
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index 4598483..2f1fcf3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -31,6 +31,7 @@
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import android.widget.ScrollView;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -123,6 +124,9 @@
final TextView footerTitle2 = findViewById(R.id.footer_title_2);
footerTitle1.setText(getFooterTitle1());
footerTitle2.setText(getFooterTitle2());
+
+ final ScrollView scrollView = findViewById(R.id.sud_scroll_view);
+ scrollView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
index 89d923d..29066b8 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
@@ -53,6 +53,8 @@
@VisibleForTesting
AudioDeviceAttributes mAudioDevice;
+ private boolean mIsAvailable;
+
public BluetoothDetailsSpatialAudioController(
Context context,
PreferenceFragmentCompat fragment,
@@ -61,16 +63,13 @@
super(context, fragment, device, lifecycle);
AudioManager audioManager = context.getSystemService(AudioManager.class);
mSpatializer = audioManager.getSpatializer();
- mAudioDevice = new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
- mCachedDevice.getAddress());
+ getAvailableDevice();
}
@Override
public boolean isAvailable() {
- return mSpatializer.isAvailableForDevice(mAudioDevice) ? true : false;
+ return mIsAvailable;
}
@Override
@@ -152,4 +151,52 @@
pref.setOnPreferenceClickListener(this);
return pref;
}
+
+ private void getAvailableDevice() {
+ AudioDeviceAttributes a2dpDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ mCachedDevice.getAddress());
+ AudioDeviceAttributes bleHeadsetDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ mCachedDevice.getAddress());
+ AudioDeviceAttributes bleSpeakerDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ mCachedDevice.getAddress());
+ AudioDeviceAttributes bleBroadcastDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_BROADCAST,
+ mCachedDevice.getAddress());
+ AudioDeviceAttributes hearingAidDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ mCachedDevice.getAddress());
+
+ mIsAvailable = true;
+ if (mSpatializer.isAvailableForDevice(bleHeadsetDevice)) {
+ mAudioDevice = bleHeadsetDevice;
+ } else if (mSpatializer.isAvailableForDevice(bleSpeakerDevice)) {
+ mAudioDevice = bleSpeakerDevice;
+ } else if (mSpatializer.isAvailableForDevice(bleBroadcastDevice)) {
+ mAudioDevice = bleBroadcastDevice;
+ } else if (mSpatializer.isAvailableForDevice(a2dpDevice)) {
+ mAudioDevice = a2dpDevice;
+ } else {
+ mIsAvailable = mSpatializer.isAvailableForDevice(hearingAidDevice);
+ mAudioDevice = hearingAidDevice;
+ }
+
+ Log.d(TAG, "getAvailableDevice() device : "
+ + mCachedDevice.getDevice().getAnonymizedAddress()
+ + ", type : " + mAudioDevice.getType()
+ + ", is available : " + mIsAvailable);
+ }
+
+ @VisibleForTesting
+ void setAvailableDevice(AudioDeviceAttributes audioDevice) {
+ mAudioDevice = audioDevice;
+ mIsAvailable = mSpatializer.isAvailableForDevice(audioDevice);
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
index 2e0e9b5..9a92783 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
@@ -29,8 +29,11 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityStatsLogUtils;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.widget.FooterPreference;
@@ -179,6 +182,13 @@
// If one device is connected(bonded), then close this fragment.
finish();
return;
+ } else if (bondState == BluetoothDevice.BOND_BONDING) {
+ // Set the bond entry where binding process starts for logging hearing aid device info
+ final int pageId = FeatureFactory.getFactory(
+ getContext()).getMetricsFeatureProvider().getAttribution(getActivity());
+ final int bondEntry = AccessibilityStatsLogUtils.convertToHearingAidInfoBondEntry(
+ pageId);
+ HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
}
if (mSelectedDevice != null && cachedDevice != null) {
BluetoothDevice device = cachedDevice.getDevice();
diff --git a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
index ac48217..60a100d 100644
--- a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
@@ -54,8 +54,7 @@
@Override
public int getMetricsCategory() {
- // TODO(b/225117454): Need to update SettingsEnums later
- return SettingsEnums.ACCESSIBILITY;
+ return SettingsEnums.DIALOG_ACCESSIBILITY_HEARING_AID_PAIR_ANOTHER;
}
@NonNull
@@ -82,7 +81,7 @@
private void positiveButtonListener() {
new SubSettingLauncher(getActivity())
.setDestination(BluetoothPairingDetail.class.getName())
- .setSourceMetricsCategory(SettingsEnums.ACCESSIBILITY)
+ .setSourceMetricsCategory(getMetricsCategory())
.launch();
}
}
diff --git a/src/com/android/settings/dream/DreamAdapter.java b/src/com/android/settings/dream/DreamAdapter.java
index cfee12e..b81d6b6 100644
--- a/src/com/android/settings/dream/DreamAdapter.java
+++ b/src/com/android/settings/dream/DreamAdapter.java
@@ -21,6 +21,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.text.TextUtils;
+import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,10 +42,9 @@
*/
public class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<IDreamItem> mItemList;
- @LayoutRes
- private final int mLayoutRes;
private int mLastSelectedPos = -1;
private boolean mEnabled = true;
+ private SparseIntArray mLayouts = new SparseIntArray();
/**
* View holder for each {@link IDreamItem}.
@@ -83,16 +83,6 @@
mSummaryView.setVisibility(View.VISIBLE);
}
- final Drawable previewImage = item.getPreviewImage();
- if (previewImage != null) {
- mPreviewView.setImageDrawable(previewImage);
- mPreviewView.setClipToOutline(true);
- mPreviewPlaceholderView.setVisibility(View.GONE);
- } else {
- mPreviewView.setImageDrawable(null);
- mPreviewPlaceholderView.setVisibility(View.VISIBLE);
- }
-
final Drawable icon = item.isActive()
? mContext.getDrawable(R.drawable.ic_dream_check_circle)
: item.getIcon().mutate();
@@ -122,12 +112,24 @@
itemView.setClickable(true);
}
- mCustomizeButton.setOnClickListener(v -> item.onCustomizeClicked());
- mCustomizeButton.setVisibility(
- item.allowCustomization() && mEnabled ? View.VISIBLE : View.GONE);
- // This must be called AFTER itemView.setSelected above, in order to keep the
- // customize button in an unselected state.
- mCustomizeButton.setSelected(false);
+ if (item.viewType() != DreamItemViewTypes.NO_DREAM_ITEM) {
+ final Drawable previewImage = item.getPreviewImage();
+ if (previewImage != null) {
+ mPreviewView.setImageDrawable(previewImage);
+ mPreviewView.setClipToOutline(true);
+ mPreviewPlaceholderView.setVisibility(View.GONE);
+ } else {
+ mPreviewView.setImageDrawable(null);
+ mPreviewPlaceholderView.setVisibility(View.VISIBLE);
+ }
+
+ mCustomizeButton.setOnClickListener(v -> item.onCustomizeClicked());
+ mCustomizeButton.setVisibility(
+ item.allowCustomization() && mEnabled ? View.VISIBLE : View.GONE);
+ // This must be called AFTER itemView.setSelected above, in order to keep the
+ // customize button in an unselected state.
+ mCustomizeButton.setSelected(false);
+ }
setEnabledStateOnViews(itemView, mEnabled);
}
@@ -149,16 +151,22 @@
}
}
+ public DreamAdapter(SparseIntArray layouts, List<IDreamItem> itemList) {
+ mItemList = itemList;
+ mLayouts = layouts;
+ }
+
public DreamAdapter(@LayoutRes int layoutRes, List<IDreamItem> itemList) {
mItemList = itemList;
- mLayoutRes = layoutRes;
+ mLayouts.append(DreamItemViewTypes.DREAM_ITEM, layoutRes);
}
@NonNull
@Override
- public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
+ @DreamItemViewTypes.ViewType int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
- .inflate(mLayoutRes, viewGroup, false);
+ .inflate(mLayouts.get(viewType), viewGroup, false);
return new DreamViewHolder(view, viewGroup.getContext());
}
@@ -168,6 +176,11 @@
}
@Override
+ public @DreamItemViewTypes.ViewType int getItemViewType(int position) {
+ return mItemList.get(position).viewType();
+ }
+
+ @Override
public int getItemCount() {
return mItemList.size();
}
diff --git a/src/com/android/settings/dream/DreamItemViewTypes.java b/src/com/android/settings/dream/DreamItemViewTypes.java
new file mode 100644
index 0000000..b720242
--- /dev/null
+++ b/src/com/android/settings/dream/DreamItemViewTypes.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dream;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class representing a dream item view types.
+ */
+public final class DreamItemViewTypes {
+
+ /**
+ * The default dream item layout
+ */
+ public static final int DREAM_ITEM = 0;
+
+ /**
+ * The dream item layout indicating no dream item selected.
+ */
+ public static final int NO_DREAM_ITEM = 1;
+
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DreamItemViewTypes.DREAM_ITEM, DreamItemViewTypes.NO_DREAM_ITEM})
+ public @interface ViewType {}
+}
diff --git a/src/com/android/settings/dream/IDreamItem.java b/src/com/android/settings/dream/IDreamItem.java
index 49c82be..911a3cf 100644
--- a/src/com/android/settings/dream/IDreamItem.java
+++ b/src/com/android/settings/dream/IDreamItem.java
@@ -67,4 +67,11 @@
default boolean allowCustomization() {
return false;
}
+
+ /**
+ * Returns whether or not this item is the no screensaver item.
+ */
+ default @DreamItemViewTypes.ViewType int viewType() {
+ return DreamItemViewTypes.DREAM_ITEM;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
index ef81247..1f0adcf 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
@@ -22,7 +22,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothDevice;
import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.Spatializer;
@@ -57,6 +59,8 @@
private Lifecycle mSpatialAudioLifecycle;
@Mock
private PreferenceCategory mProfilesContainer;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
private BluetoothDetailsSpatialAudioController mController;
private SwitchPreference mSpatialAudioPref;
@@ -70,6 +74,8 @@
when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
+ when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
mController = new BluetoothDetailsSpatialAudioController(mContext, mFragment,
mCachedDevice, mSpatialAudioLifecycle);
@@ -83,15 +89,85 @@
}
@Test
- public void isAvailable_spatialAudioIsAvailable_returnsTrue() {
- when(mSpatializer.isAvailableForDevice(mController.mAudioDevice)).thenReturn(true);
+ public void isAvailable_spatialAudioSupportA2dpDevice_returnsTrue() {
+ AudioDeviceAttributes a2dpDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ MAC_ADDRESS);
+ when(mSpatializer.isAvailableForDevice(a2dpDevice)).thenReturn(true);
+
+ mController.setAvailableDevice(a2dpDevice);
+
assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP);
}
@Test
- public void isAvailable_spatialAudioIsNotAvailable_returnsFalse() {
- when(mSpatializer.isAvailableForDevice(mController.mAudioDevice)).thenReturn(false);
+ public void isAvailable_spatialAudioSupportBleHeadsetDevice_returnsTrue() {
+ AudioDeviceAttributes bleHeadsetDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ MAC_ADDRESS);
+ when(mSpatializer.isAvailableForDevice(bleHeadsetDevice)).thenReturn(true);
+
+ mController.setAvailableDevice(bleHeadsetDevice);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_BLE_HEADSET);
+ }
+
+ @Test
+ public void isAvailable_spatialAudioSupportBleSpeakerDevice_returnsTrue() {
+ AudioDeviceAttributes bleSpeakerDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ MAC_ADDRESS);
+ when(mSpatializer.isAvailableForDevice(bleSpeakerDevice)).thenReturn(true);
+
+ mController.setAvailableDevice(bleSpeakerDevice);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_BLE_SPEAKER);
+ }
+
+ @Test
+ public void isAvailable_spatialAudioSupportBleBroadcastDevice_returnsTrue() {
+ AudioDeviceAttributes bleBroadcastDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_BROADCAST,
+ MAC_ADDRESS);
+ when(mSpatializer.isAvailableForDevice(bleBroadcastDevice)).thenReturn(true);
+
+ mController.setAvailableDevice(bleBroadcastDevice);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_BLE_BROADCAST);
+ }
+
+ @Test
+ public void isAvailable_spatialAudioSupportHearingAidDevice_returnsTrue() {
+ AudioDeviceAttributes hearingAidDevice = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ MAC_ADDRESS);
+ when(mSpatializer.isAvailableForDevice(hearingAidDevice)).thenReturn(true);
+
+ mController.setAvailableDevice(hearingAidDevice);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_HEARING_AID);
+ }
+
+ @Test
+ public void isAvailable_spatialAudioNotSupported_returnsFalse() {
assertThat(mController.isAvailable()).isFalse();
+ assertThat(mController.mAudioDevice.getType())
+ .isEqualTo(AudioDeviceInfo.TYPE_HEARING_AID);
}
@Test
diff --git a/tests/unit/src/com/android/settings/applications/AppStateAppBatteryUsageBridgeTest.java b/tests/unit/src/com/android/settings/applications/AppStateAppBatteryUsageBridgeTest.java
new file mode 100644
index 0000000..c49b4cd
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/AppStateAppBatteryUsageBridgeTest.java
@@ -0,0 +1,78 @@
+package com.android.settings.applications;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public final class AppStateAppBatteryUsageBridgeTest {
+ private static final String TEST_PACKAGE_1 = "com.example.test.pkg1";
+ private static final String TEST_PACKAGE_2 = "com.example.test.pkg2";
+ private static final int UID_1 = 12345;
+ private static final int UID_2 = 7654321;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private PowerAllowlistBackend mPowerAllowlistBackend;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void updateExtraInfo_updatesRestricted() {
+ when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1)).thenReturn(false);
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ UID_1, TEST_PACKAGE_1)).thenReturn(AppOpsManager.MODE_IGNORED);
+ AppStateAppBatteryUsageBridge bridge =
+ new AppStateAppBatteryUsageBridge(mContext, null, null);
+ bridge.mAppOpsManager = mAppOpsManager;
+ bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
+ AppEntry entry = new AppEntry(mContext, null, 0);
+
+ bridge.updateExtraInfo(entry, TEST_PACKAGE_1, UID_1);
+
+ assertThat(entry.extraInfo.getClass())
+ .isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
+ assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
+ .isEqualTo(AppStateAppBatteryUsageBridge.MODE_RESTRICTED);
+ }
+
+ @Test
+ public void updateExtraInfo_updatesUnrestricted() {
+ when(mPowerAllowlistBackend.isAllowlisted(TEST_PACKAGE_1)).thenReturn(true);
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ UID_2, TEST_PACKAGE_2)).thenReturn(AppOpsManager.MODE_ALLOWED);
+ AppStateAppBatteryUsageBridge bridge =
+ new AppStateAppBatteryUsageBridge(mContext, null, null);
+ bridge.mAppOpsManager = mAppOpsManager;
+ bridge.mPowerAllowlistBackend = mPowerAllowlistBackend;
+ AppEntry entry = new AppEntry(mContext, null, 0);
+
+ bridge.updateExtraInfo(entry, TEST_PACKAGE_2, UID_2);
+
+ assertThat(entry.extraInfo.getClass())
+ .isEqualTo(AppStateAppBatteryUsageBridge.AppBatteryUsageDetails.class);
+ assertThat(AppStateAppBatteryUsageBridge.getAppBatteryUsageDetailsMode(entry))
+ .isEqualTo(AppStateAppBatteryUsageBridge.MODE_UNRESTRICTED);
+ }
+}