diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c5e512eeefc..7807f0e07d9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -69,6 +69,7 @@
+
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 7b0be943bc5..5ab543f65d9 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -172,8 +172,9 @@ public final class CredentialStorage extends FragmentActivity {
dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
return;
}
- installIfAvailable();
- finish();
+ if (installIfAvailable()) {
+ finish();
+ }
return;
}
}
@@ -217,10 +218,13 @@ public final class CredentialStorage extends FragmentActivity {
/**
* Install credentials if available, otherwise do nothing.
+ *
+ * @return true if the installation is done and the activity should be finished, false if
+ * an asynchronous task is pending and will finish the activity when it's done.
*/
- private void installIfAvailable() {
+ private boolean installIfAvailable() {
if (mInstallBundle == null || mInstallBundle.isEmpty()) {
- return;
+ return true;
}
final Bundle bundle = mInstallBundle;
@@ -235,16 +239,17 @@ public final class CredentialStorage extends FragmentActivity {
if (uid != Process.WIFI_UID) {
Log.e(TAG, "Failed to install credentials as uid " + uid + ": cross-user installs"
+ " may only target wifi uids");
- return;
+ return true;
}
final Intent installIntent = new Intent(ACTION_INSTALL)
.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
.putExtras(bundle);
startActivityAsUser(installIntent, new UserHandle(dstUserId));
- return;
+ return true;
}
+ boolean shouldFinish = true;
if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
@@ -259,7 +264,7 @@ public final class CredentialStorage extends FragmentActivity {
if (!mKeyStore.importKey(key, value, uid, flags)) {
Log.e(TAG, "Failed to install " + key + " as uid " + uid);
- return;
+ return true;
}
// The key was prepended USER_PRIVATE_KEY by the CredentialHelper. However,
// KeyChain internally uses the raw alias name and only prepends USER_PRIVATE_KEY
@@ -270,6 +275,7 @@ public final class CredentialStorage extends FragmentActivity {
if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
new MarkKeyAsUserSelectable(
key.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, "")).execute();
+ shouldFinish = false;
}
}
@@ -281,7 +287,7 @@ public final class CredentialStorage extends FragmentActivity {
if (!mKeyStore.put(certName, certData, uid, flags)) {
Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
- return;
+ return shouldFinish;
}
}
@@ -291,7 +297,7 @@ public final class CredentialStorage extends FragmentActivity {
if (!mKeyStore.put(caListName, caListData, uid, flags)) {
Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
- return;
+ return shouldFinish;
}
}
@@ -300,6 +306,7 @@ public final class CredentialStorage extends FragmentActivity {
sendBroadcast(broadcast);
setResult(RESULT_OK);
+ return shouldFinish;
}
/**
@@ -411,6 +418,13 @@ public final class CredentialStorage extends FragmentActivity {
return false;
}
}
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ Log.i(TAG, String.format("Marked alias %s as selectable, success? %s",
+ mAlias, result));
+ CredentialStorage.this.finish();
+ }
}
/**
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 46794364156..5d6a4128768 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -14,11 +14,7 @@
package com.android.settings.display;
import android.content.Context;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
+import android.hardware.display.ColorDisplayManager;
import androidx.annotation.VisibleForTesting;
@@ -29,19 +25,16 @@ import com.android.settings.core.BasePreferenceController;
public class ColorModePreferenceController extends BasePreferenceController {
private static final String TAG = "ColorModePreference";
- private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT = 1030;
-
- private final ConfigurationWrapper mConfigWrapper;
private ColorDisplayController mColorDisplayController;
public ColorModePreferenceController(Context context, String key) {
super(context, key);
- mConfigWrapper = new ConfigurationWrapper();
}
@Override
public int getAvailabilityStatus() {
- return mConfigWrapper.isDeviceColorManaged()
+ return mContext.getSystemService(ColorDisplayManager.class)
+ .isDeviceColorManaged()
&& !getColorDisplayController().getAccessibilityTransformActivated() ?
AVAILABLE_UNSEARCHABLE : DISABLED_FOR_USER;
}
@@ -68,32 +61,4 @@ public class ColorModePreferenceController extends BasePreferenceController {
}
return mColorDisplayController;
}
-
- @VisibleForTesting
- static class ConfigurationWrapper {
- private final IBinder mSurfaceFlinger;
-
- ConfigurationWrapper() {
- mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
- }
-
- boolean isDeviceColorManaged() {
- if (mSurfaceFlinger != null) {
- final Parcel data = Parcel.obtain();
- final Parcel reply = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- try {
- mSurfaceFlinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT,
- data, reply, 0);
- return reply.readBoolean();
- } catch (RemoteException ex) {
- Log.e(TAG, "Failed to query color management support", ex);
- } finally {
- data.recycle();
- reply.recycle();
- }
- }
- return false;
- }
- }
}
diff --git a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
index 8ad5e630e2b..1710f515160 100644
--- a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.display;
import android.content.Context;
-
import android.hardware.display.ColorDisplayManager;
import androidx.preference.DropDownPreference;
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index 4378be3f0d7..8720a3ce488 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -69,9 +69,9 @@ public class SliceContextualCardController implements ContextualCardController {
dbHelper.markContextualCardAsDismissed(mContext, card.getName());
});
showFeedbackDialog(card);
- final ContextualCardFeatureProvider contexualCardFeatureProvider =
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
- contexualCardFeatureProvider.logContextualCardDismiss(mContext, card);
+ contextualCardFeatureProvider.logContextualCardDismiss(mContext, card);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index a2d6e2b119c..4df2a04cd9e 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -28,8 +28,11 @@ import android.widget.ViewFlipper;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
@@ -51,13 +54,15 @@ import java.util.Set;
* Card renderer for {@link ContextualCard} built as slices.
*/
public class SliceContextualCardRenderer implements ContextualCardRenderer,
- SliceView.OnSliceActionListener {
+ SliceView.OnSliceActionListener, LifecycleObserver {
public static final int VIEW_TYPE = R.layout.homepage_slice_tile;
private static final String TAG = "SliceCardRenderer";
@VisibleForTesting
final Map> mSliceLiveDataMap;
+ @VisibleForTesting
+ final Set mFlippedCardSet;
private final Context mContext;
private final LifecycleOwner mLifecycleOwner;
@@ -71,6 +76,8 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
mSliceLiveDataMap = new ArrayMap<>();
mControllerRendererPool = controllerRendererPool;
mCardSet = new ArraySet<>();
+ mFlippedCardSet = new ArraySet<>();
+ mLifecycleOwner.getLifecycle().addObserver(this);
}
@Override
@@ -122,20 +129,23 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
}
private void initDismissalActions(SliceViewHolder cardHolder, ContextualCard card) {
- final ViewFlipper viewFlipper = cardHolder.itemView.findViewById(R.id.viewFlipper);
cardHolder.sliceView.setOnLongClickListener(v -> {
- viewFlipper.showNext();
+ cardHolder.viewFlipper.showNext();
+ mFlippedCardSet.add(cardHolder);
return true;
});
final Button btnKeep = cardHolder.itemView.findViewById(R.id.keep);
btnKeep.setOnClickListener(v -> {
- viewFlipper.showPrevious();
+ cardHolder.resetCard();
+ mFlippedCardSet.remove(cardHolder);
});
final Button btnRemove = cardHolder.itemView.findViewById(R.id.remove);
btnRemove.setOnClickListener(v -> {
mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
+ cardHolder.resetCard();
+ mFlippedCardSet.remove(cardHolder);
});
}
@@ -158,12 +168,24 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
}
}
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mFlippedCardSet.stream().forEach(holder -> holder.resetCard());
+ mFlippedCardSet.clear();
+ }
+
public static class SliceViewHolder extends RecyclerView.ViewHolder {
public final SliceView sliceView;
+ public final ViewFlipper viewFlipper;
public SliceViewHolder(View view) {
super(view);
sliceView = view.findViewById(R.id.slice_view);
+ viewFlipper = view.findViewById(R.id.viewFlipper);
+ }
+
+ public void resetCard() {
+ viewFlipper.setDisplayedChild(0);
}
}
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index 13a2bc5ba87..11d0106565c 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -18,6 +18,7 @@ package com.android.settings.homepage.contextualcards.slices;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.app.Activity;
@@ -51,10 +52,14 @@ import org.robolectric.android.controller.ActivityController;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceContextualCardRendererTest {
+ private static final String TEST_SLICE_URI = "content://test/test";
+
@Mock
private LiveData mSliceLiveData;
@Mock
private ControllerRendererPool mControllerRendererPool;
+ @Mock
+ private SliceContextualCardController mController;
private Activity mActivity;
private SliceContextualCardRenderer mRenderer;
@@ -75,10 +80,9 @@ public class SliceContextualCardRendererTest {
@Test
public void bindView_shouldSetScrollableToFalse() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
assertThat(
((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.isScrollable
@@ -99,64 +103,107 @@ public class SliceContextualCardRendererTest {
@Test
public void bindView_newSliceLiveData_shouldAddDataToMap() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
-
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
assertThat(mRenderer.mSliceLiveDataMap.size()).isEqualTo(1);
}
@Test
public void bindView_sliceLiveDataShouldObserveSliceView() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
-
- assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue();
+ assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isTrue();
}
@Test
public void bindView_sliceLiveDataShouldRemoveObservers() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
- mRenderer.mSliceLiveDataMap.put(sliceUri, mSliceLiveData);
+ mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
verify(mSliceLiveData).removeObservers(mLifecycleOwner);
}
@Test
public void longClick_shouldFlipCard() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
- assertThat(card).isNotNull();
card.performLongClick();
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
}
+ @Test
+ public void longClick_shouldAddViewHolderToSet() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+
+ assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
+ }
+
@Test
public void viewClick_keepCard_shouldFlipBackToSlice() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
- assertThat(card).isNotNull();
card.performLongClick();
- assertThat(btnKeep).isNotNull();
btnKeep.performClick();
assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
}
+ @Test
+ public void viewClick_keepCard_shouldRemoveViewHolderFromSet() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+ btnKeep.performClick();
+
+ assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
+ }
+
+ @Test
+ public void viewClick_removeCard_shouldRemoveViewHolderFromSet() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
+ final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
+ mRenderer.bindView(viewHolder, contextualCard);
+ doReturn(mController).when(mControllerRendererPool).getController(mActivity,
+ ContextualCard.CardType.SLICE);
+
+ card.performLongClick();
+ btnRemove.performClick();
+
+ assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
+ }
+
+ @Test
+ public void onStop_cardIsFlipped_shouldFlipBack() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+ mRenderer.onStop();
+
+ assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
+ }
+
private RecyclerView.ViewHolder getSliceViewHolder() {
final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
final RecyclerView recyclerView = new RecyclerView(mActivity);
@@ -169,6 +216,7 @@ public class SliceContextualCardRendererTest {
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
.setName("test_name")
+ .setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(Uri.parse(sliceUri))
.build();
}