diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bbb8eea9700..6c0dbff5b06 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4179,11 +4179,6 @@
-
-
-
-
-
@@ -4196,6 +4191,21 @@
android:value="true" />
+
+
+
+
+
+
+
+
+
+
launchPairingDetail());
}
@Override
protected void refresh() {
+ updateButtonPreferenceTitle(mPreference);
mPreference.setVisible(getButtonPreferenceVisibility(mCachedDevice));
+
+ }
+
+ private void updateButtonPreferenceTitle(ButtonPreference preference) {
+ final int side = mCachedDevice.getDeviceSide();
+ final int stringRes = (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
+ ? R.string.bluetooth_pair_right_ear_button
+ : R.string.bluetooth_pair_left_ear_button;
+
+ preference.setTitle(stringRes);
}
private boolean getButtonPreferenceVisibility(CachedBluetoothDevice cachedDevice) {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index c6f64d602ca..0f6db8a9291 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -77,6 +77,7 @@ import com.android.settings.bluetooth.BluetoothFindBroadcastsFragment;
import com.android.settings.bluetooth.BluetoothPairingDetail;
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.NfcAndPaymentFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
@@ -349,7 +350,8 @@ public class SettingsGateway {
MobileNetworkSettings.class.getName(),
AppLocaleDetails.class.getName(),
TurnScreenOnSettings.class.getName(),
- TurnScreenOnDetails.class.getName()
+ TurnScreenOnDetails.class.getName(),
+ NfcAndPaymentFragment.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/dream/DreamAdapter.java b/src/com/android/settings/dream/DreamAdapter.java
index cfee12e0f42..b81d6b6d679 100644
--- a/src/com/android/settings/dream/DreamAdapter.java
+++ b/src/com/android/settings/dream/DreamAdapter.java
@@ -21,6 +21,7 @@ import android.content.Context;
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 @@ import java.util.List;
*/
public class DreamAdapter extends RecyclerView.Adapter {
private final List 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 @@ public class DreamAdapter extends RecyclerView.Adapter
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 @@ public class DreamAdapter extends RecyclerView.Adapter
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 class DreamAdapter extends RecyclerView.Adapter
}
}
+ public DreamAdapter(SparseIntArray layouts, List itemList) {
+ mItemList = itemList;
+ mLayouts = layouts;
+ }
+
public DreamAdapter(@LayoutRes int layoutRes, List 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());
}
@@ -167,6 +175,11 @@ public class DreamAdapter extends RecyclerView.Adapter
((DreamViewHolder) viewHolder).bindView(mItemList.get(i), i);
}
+ @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 00000000000..b7202429769
--- /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 49c82bec42a..911a3cf0bd2 100644
--- a/src/com/android/settings/dream/IDreamItem.java
+++ b/src/com/android/settings/dream/IDreamItem.java
@@ -67,4 +67,11 @@ public interface IDreamItem {
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/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
index 77c0f685bd2..556ea579a83 100644
--- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
@@ -22,6 +22,7 @@ import android.app.AppOpsManager.MODE_DEFAULT
import android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES
import android.content.Context
import android.content.pm.ApplicationInfo
+import android.os.UserManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R
@@ -49,6 +50,10 @@ class InstallUnknownAppsListModel(private val context: Context) :
override val pageTitleResId = R.string.install_other_apps
override val switchTitleResId = R.string.external_source_switch_title
override val footerResId = R.string.install_all_warning
+ override val switchRestrictionKeys = listOf(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+ )
override fun transformItem(app: ApplicationInfo) = InstallUnknownAppsRecord(
app = app,
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
index cfa6d41e0d7..d01e3ac4d58 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
@@ -56,7 +56,7 @@ public class BluetoothDetailsPairOtherControllerTest extends BluetoothDetailsCon
}
@Test
- public void init_leftSideDevice_expectedTitle() {
+ public void init_leftSideDevice_rightSideButtonTitle() {
when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_LEFT);
mController.init(mScreen);
@@ -66,7 +66,7 @@ public class BluetoothDetailsPairOtherControllerTest extends BluetoothDetailsCon
}
@Test
- public void init_rightSideDevice_expectedTitle() {
+ public void init_rightSideDevice_leftSideButtonTitle() {
when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
mController.init(mScreen);
@@ -118,4 +118,15 @@ public class BluetoothDetailsPairOtherControllerTest extends BluetoothDetailsCon
assertThat(mController.isAvailable()).isTrue();
}
+
+ @Test
+ public void refresh_leftSideDevice_leftSideButtonTitle() {
+ when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+ mController.init(mScreen);
+
+ mController.refresh();
+
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.bluetooth_pair_left_ear_button));
+ }
}
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 00000000000..c49b4cd8d2f
--- /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);
+ }
+}