diff options
author | Diego Valenzuela <dvalenzuela@google.com> | 2022-09-26 19:50:17 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-09-26 19:50:17 +0000 |
commit | 2468ae8a0dda1d6af5d92a0d0286e56f18c66031 (patch) | |
tree | d1b8b10a998a749107307c54fa65277a2223e29d | |
parent | 1961fc6ede74ffbad33d5c9f987af062ea88978b (diff) | |
parent | 1885f5f5194db1ba4233b48c47d99f975c9b0386 (diff) | |
download | support-2468ae8a0dda1d6af5d92a0d0286e56f18c66031.tar.gz |
Merge "Add API to communicate if the car supports AppDrivenRefresh Relnote: New Api to allow users detect if an OEM has enabled App Driven Refresh Bug:b/243957836 Video: go/a4c-refresh-video Test: Unit + Manual" into androidx-main
8 files changed, 80 insertions, 23 deletions
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java index 34c1e318f66..ac18ac83f53 100644 --- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java +++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java @@ -46,6 +46,7 @@ import androidx.core.graphics.drawable.IconCompat; import java.util.ArrayList; import java.util.List; +import java.util.Random; /** Provides sample place data used in the demos. */ public class SamplePlaces { @@ -242,7 +243,7 @@ public class SamplePlaces { /** Return the {@link ItemList} of the sample places. */ @NonNull - public ItemList getPlaceList() { + public ItemList getPlaceList(boolean randomOrder) { ItemList.Builder listBuilder = new ItemList.Builder(); int listLimit = 6; @@ -258,8 +259,13 @@ public class SamplePlaces { listLimit = min(listLimit, mPlaces.size()); for (int index = 0; index < listLimit; index++) { - PlaceInfo place = mPlaces.get(index); - + Random rand = new Random(); + PlaceInfo place; + if (randomOrder) { + place = mPlaces.get(rand.nextInt(listLimit)); + } else { + place = mPlaces.get(index); + } // Build a description string that includes the required distance span. int distanceKm = getDistanceFromCurrentLocation(place.location) / 1000; SpannableString description = new SpannableString(" \u00b7 " + place.description); diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java index 0db39baa49f..8f12eec8d21 100644 --- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java +++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/PlaceListNavigationTemplateDemoScreen.java @@ -18,10 +18,14 @@ package androidx.car.app.sample.showcase.common.navigation; import static androidx.car.app.CarToast.LENGTH_SHORT; +import android.os.Handler; +import android.os.Looper; + import androidx.annotation.NonNull; import androidx.car.app.CarContext; import androidx.car.app.CarToast; import androidx.car.app.Screen; +import androidx.car.app.constraints.ConstraintManager; import androidx.car.app.model.Action; import androidx.car.app.model.ActionStrip; import androidx.car.app.model.CarIcon; @@ -39,14 +43,27 @@ public final class PlaceListNavigationTemplateDemoScreen extends Screen { private boolean mIsFavorite = false; + private boolean mIsAppRefresh = false; + public PlaceListNavigationTemplateDemoScreen(@NonNull CarContext carContext) { super(carContext); mPlaces = SamplePlaces.create(this); } + private final Handler mHandler = new Handler(Looper.getMainLooper()); + @NonNull @Override public Template onGetTemplate() { + boolean isAppDrivenRefreshEnabled = this.getCarContext().getCarService( + ConstraintManager.class).isAppDrivenRefreshEnabled(); + + if (isAppDrivenRefreshEnabled && !mIsAppRefresh) { + mIsAppRefresh = true; + for (int i = 1; i <= 10; i++) { + mHandler.postDelayed(this::invalidate, i * 1000L); + } + } Header header = new Header.Builder() .setStartHeaderAction(Action.BACK) .addEndHeaderAction(new Action.Builder() @@ -73,7 +90,7 @@ public final class PlaceListNavigationTemplateDemoScreen extends Screen { }) .build()) .addEndHeaderAction(new Action.Builder() - .setOnClickListener(() -> finish()) + .setOnClickListener(this::finish) .setIcon( new CarIcon.Builder( IconCompat.createWithResource( @@ -83,9 +100,9 @@ public final class PlaceListNavigationTemplateDemoScreen extends Screen { .build()) .setTitle(getCarContext().getString(R.string.place_list_nav_template_demo_title)) .build(); - + //Return elements in random order. return new PlaceListNavigationTemplate.Builder() - .setItemList(mPlaces.getPlaceList()) + .setItemList(mPlaces.getPlaceList(/*randomOrder=*/isAppDrivenRefreshEnabled)) .setHeader(header) .setMapActionStrip(RoutingDemoModels.getMapActionStrip(getCarContext())) .setActionStrip( diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java index a64bf4a9a0e..9d257bba2ba 100644 --- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java +++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/PlaceListTemplateDemoScreen.java @@ -38,7 +38,7 @@ public final class PlaceListTemplateDemoScreen extends Screen { @Override public Template onGetTemplate() { return new PlaceListMapTemplate.Builder() - .setItemList(mPlaces.getPlaceList()) + .setItemList(mPlaces.getPlaceList(/*randomOrder=*/false)) .setTitle(getCarContext().getString(R.string.place_list_template_demo_title)) .setHeaderAction(Action.BACK) .build(); diff --git a/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt b/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt index 514019a66a6..89bff07ca3e 100644 --- a/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt +++ b/car/app/app/api/public_plus_experimental_1.3.0-beta02.txt @@ -228,6 +228,7 @@ package androidx.car.app.constraints { @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager { method public int getContentLimit(int); + method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled(); field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1 field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0 field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4 diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt index 514019a66a6..89bff07ca3e 100644 --- a/car/app/app/api/public_plus_experimental_current.txt +++ b/car/app/app/api/public_plus_experimental_current.txt @@ -228,6 +228,7 @@ package androidx.car.app.constraints { @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager { method public int getContentLimit(int); + method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled(); field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1 field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0 field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4 diff --git a/car/app/app/src/main/aidl/androidx/car/app/constraints/IConstraintHost.aidl b/car/app/app/src/main/aidl/androidx/car/app/constraints/IConstraintHost.aidl index 3f1b7d4f74d..0e058afd707 100644 --- a/car/app/app/src/main/aidl/androidx/car/app/constraints/IConstraintHost.aidl +++ b/car/app/app/src/main/aidl/androidx/car/app/constraints/IConstraintHost.aidl @@ -24,4 +24,9 @@ interface IConstraintHost { * Queries the host for the limit for a content type. */ int getContentLimit(int contentType) = 1; + + /** + * Queries the host for the ability to support App Driven Refresh. + */ + boolean isAppDrivenRefreshEnabled() = 2; } diff --git a/car/app/app/src/main/java/androidx/car/app/constraints/ConstraintManager.java b/car/app/app/src/main/java/androidx/car/app/constraints/ConstraintManager.java index 4e025f35b88..121dc31073e 100644 --- a/car/app/app/src/main/java/androidx/car/app/constraints/ConstraintManager.java +++ b/car/app/app/src/main/java/androidx/car/app/constraints/ConstraintManager.java @@ -31,6 +31,7 @@ import androidx.car.app.CarContext; import androidx.car.app.HostDispatcher; import androidx.car.app.HostException; import androidx.car.app.R; +import androidx.car.app.annotations.ExperimentalCarApi; import androidx.car.app.annotations.RequiresCarApi; import androidx.car.app.managers.Manager; import androidx.car.app.utils.LogTags; @@ -120,9 +121,8 @@ public class ConstraintManager implements Manager { // TODO(b/185805900): consider caching these values if performance is a concern. limit = mHostDispatcher.dispatchForResult( CarContext.CONSTRAINT_SERVICE, - "getContentLimit", (IConstraintHost host) -> { - return host.getContentLimit(contentLimitType); - } + "getContentLimit", + (IConstraintHost host) -> host.getContentLimit(contentLimitType) ); } catch (RemoteException e) { // The host is dead, don't crash the app, just log. @@ -166,7 +166,29 @@ public class ConstraintManager implements Manager { return new ConstraintManager(requireNonNull(context), requireNonNull(hostDispatcher)); } - private ConstraintManager(CarContext context, HostDispatcher hostDispatcher) { + /** + * Determines if the app supports app Driven Refresh Enabled + */ + @RequiresCarApi(6) + @ExperimentalCarApi + public boolean isAppDrivenRefreshEnabled() { + Boolean result; + try { + // TODO(b/185805900): consider caching these values if performance is a concern. + result = mHostDispatcher.dispatchForResult( + CarContext.CONSTRAINT_SERVICE, + "isAppDrivenRefreshEnabled", IConstraintHost::isAppDrivenRefreshEnabled + ); + return Boolean.TRUE.equals(result); + } catch (RemoteException e) { + // The host is dead, don't crash the app, just log. + Log.w(LogTags.TAG, "Failed to retrieve list limit from the host, using defaults", e); + } + // Returns default values as documented if host call failed. + return false; + } + + private ConstraintManager(@NonNull CarContext context, @NonNull HostDispatcher hostDispatcher) { mCarContext = context; mHostDispatcher = hostDispatcher; } diff --git a/car/app/app/src/test/java/androidx/car/app/constraints/ConstraintManagerTest.java b/car/app/app/src/test/java/androidx/car/app/constraints/ConstraintManagerTest.java index f152848401a..1329d7d79bd 100644 --- a/car/app/app/src/test/java/androidx/car/app/constraints/ConstraintManagerTest.java +++ b/car/app/app/src/test/java/androidx/car/app/constraints/ConstraintManagerTest.java @@ -72,6 +72,11 @@ public class ConstraintManagerTest { public int getContentLimit(int contentType) throws RemoteException { return mMockConstraintHost.getContentLimit(contentType); } + + @Override + public boolean isAppDrivenRefreshEnabled() throws RemoteException { + return mMockConstraintHost.isAppDrivenRefreshEnabled(); + } }; when(mMockCarHost.getHost(any())).thenReturn(hostStub.asBinder()); mHostDispatcher.setCarHost(mMockCarHost); @@ -91,17 +96,17 @@ public class ConstraintManagerTest { } @Test - public void host_returnLimits() throws RemoteException { - when(mMockConstraintHost.getContentLimit(CONTENT_LIMIT_TYPE_LIST)).thenReturn(1); - when(mMockConstraintHost.getContentLimit(CONTENT_LIMIT_TYPE_GRID)).thenReturn(2); - when(mMockConstraintHost.getContentLimit(CONTENT_LIMIT_TYPE_PLACE_LIST)).thenReturn(3); - when(mMockConstraintHost.getContentLimit(CONTENT_LIMIT_TYPE_ROUTE_LIST)).thenReturn(4); - when(mMockConstraintHost.getContentLimit(CONTENT_LIMIT_TYPE_PANE)).thenReturn(5); - - assertThat(mConstraintManager.getContentLimit(CONTENT_LIMIT_TYPE_LIST)).isEqualTo(1); - assertThat(mConstraintManager.getContentLimit(CONTENT_LIMIT_TYPE_GRID)).isEqualTo(2); - assertThat(mConstraintManager.getContentLimit(CONTENT_LIMIT_TYPE_PLACE_LIST)).isEqualTo(3); - assertThat(mConstraintManager.getContentLimit(CONTENT_LIMIT_TYPE_ROUTE_LIST)).isEqualTo(4); - assertThat(mConstraintManager.getContentLimit(CONTENT_LIMIT_TYPE_PANE)).isEqualTo(5); + public void host_throwsException_returnsDefault() throws RemoteException { + when(mMockConstraintHost.isAppDrivenRefreshEnabled()).thenThrow(new RemoteException()); + + assertThat(mConstraintManager.isAppDrivenRefreshEnabled()).isFalse(); + } + + @Test + public void host_returAppDrivenRefreshEnabled() throws RemoteException { + when(mMockConstraintHost.isAppDrivenRefreshEnabled()).thenReturn(true); + + + assertThat(mConstraintManager.isAppDrivenRefreshEnabled()).isTrue(); } } |