diff options
Diffstat (limited to 'car-lib/src/android/car/cluster')
4 files changed, 185 insertions, 17 deletions
diff --git a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java index 54d10e2f1c..2b633a0093 100644 --- a/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java +++ b/car-lib/src/android/car/cluster/CarInstrumentClusterManager.java @@ -17,10 +17,10 @@ package android.car.cluster; import android.annotation.SystemApi; +import android.car.Car; import android.car.CarManagerBase; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; /** @@ -35,7 +35,7 @@ import android.os.IBinder; */ @Deprecated @SystemApi -public class CarInstrumentClusterManager implements CarManagerBase { +public class CarInstrumentClusterManager extends CarManagerBase { /** * @deprecated use {@link android.car.Car#CATEGORY_NAVIGATION} instead * @@ -101,7 +101,8 @@ public class CarInstrumentClusterManager implements CarManagerBase { } /** @hide */ - public CarInstrumentClusterManager(IBinder service, Handler handler) { + public CarInstrumentClusterManager(Car car, IBinder service) { + super(car); // No-op } diff --git a/car-lib/src/android/car/cluster/renderer/IInstrumentCluster.aidl b/car-lib/src/android/car/cluster/renderer/IInstrumentCluster.aidl index 7deecc747b..4f417961cc 100644 --- a/car-lib/src/android/car/cluster/renderer/IInstrumentCluster.aidl +++ b/car-lib/src/android/car/cluster/renderer/IInstrumentCluster.aidl @@ -28,6 +28,8 @@ interface IInstrumentCluster { /** * Returns {@link IInstrumentClusterNavigation} that will be passed to the navigation * application. + * + * TODO(b/141992448) : remove blocking call */ IInstrumentClusterNavigation getNavigationService(); diff --git a/car-lib/src/android/car/cluster/renderer/IInstrumentClusterHelper.aidl b/car-lib/src/android/car/cluster/renderer/IInstrumentClusterHelper.aidl new file mode 100644 index 0000000000..680e24198e --- /dev/null +++ b/car-lib/src/android/car/cluster/renderer/IInstrumentClusterHelper.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 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 android.car.cluster.renderer; + +import android.content.Intent; +import android.os.Bundle; + +/** + * Helper binder API for InstrumentClusterRenderingService. This contains binder calls to car + * service. + * + * @hide + */ +interface IInstrumentClusterHelper { + /** + * Start an activity to specified display / user. The activity is considered as + * in fixed mode for the display and will be re-launched if the activity crashes, the package + * is updated or goes to background for whatever reason. + * Only one activity can exist in fixed mode for the target display and calling this multiple + * times with different {@code Intent} will lead into making all previous activities into + * non-fixed normal state (= will not be re-launched.) + * + * Do not change binder transaction number. + */ + boolean startFixedActivityModeForDisplayAndUser(in Intent intent, + in Bundle activityOptionsBundle, int userId) = 0; + /** + * The activity lauched on the display is no longer in fixed mode. Re-launching or finishing + * should not trigger re-launfhing any more. Note that Activity for non-current user will + * be auto-stopped and there is no need to call this for user swiching. Note that this does not + * stop the activity but it will not be re-launched any more. + * + * Do not change binder transaction number. + */ + void stopFixedActivityMode(int displayId) = 1; +} diff --git a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java index 6996119715..ede4b6ad07 100644 --- a/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java +++ b/car-lib/src/android/car/cluster/renderer/InstrumentClusterRenderingService.java @@ -22,6 +22,7 @@ import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.UserIdInt; import android.app.ActivityOptions; import android.app.Service; import android.car.Car; @@ -82,20 +83,35 @@ import java.util.stream.Collectors; */ @SystemApi public abstract class InstrumentClusterRenderingService extends Service { + /** + * Key to pass IInstrumentClusterHelper binder in onBind call {@link Intent} through extra + * {@link Bundle). Both extra bundle and binder itself use this key. + * + * @hide + */ + public static final String EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER = + "android.car.cluster.renderer.IInstrumentClusterHelper"; + private static final String TAG = CarLibLog.TAG_CLUSTER; private static final String BITMAP_QUERY_WIDTH = "w"; private static final String BITMAP_QUERY_HEIGHT = "h"; + private static final String BITMAP_QUERY_OFFLANESALPHA = "offLanesAlpha"; + + private final Handler mUiHandler = new Handler(Looper.getMainLooper()); private final Object mLock = new Object(); + // Main thread only private RendererBinder mRendererBinder; - private Handler mUiHandler = new Handler(Looper.getMainLooper()); private ActivityOptions mActivityOptions; private ClusterActivityState mActivityState; private ComponentName mNavigationComponent; @GuardedBy("mLock") private ContextOwner mNavContextOwner; + @GuardedBy("mLock") + private IInstrumentClusterHelper mInstrumentClusterHelper; + private static final int IMAGE_CACHE_SIZE_BYTES = 4 * 1024 * 1024; /* 4 mb */ private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>( IMAGE_CACHE_SIZE_BYTES) { @@ -157,6 +173,18 @@ public abstract class InstrumentClusterRenderingService extends Service { Log.d(TAG, "onBind, intent: " + intent); } + Bundle bundle = intent.getBundleExtra(EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER); + IBinder binder = null; + if (bundle != null) { + binder = bundle.getBinder(EXTRA_BUNDLE_KEY_FOR_INSTRUMENT_CLUSTER_HELPER); + } + if (binder == null) { + Log.wtf(TAG, "IInstrumentClusterHelper not passed through binder"); + } else { + synchronized (mLock) { + mInstrumentClusterHelper = IInstrumentClusterHelper.Stub.asInterface(binder); + } + } if (mRendererBinder == null) { mRendererBinder = new RendererBinder(getNavigationRenderer()); } @@ -196,6 +224,76 @@ public abstract class InstrumentClusterRenderingService extends Service { public void onNavigationComponentReleased() { } + @Nullable + private IInstrumentClusterHelper getClusterHelper() { + synchronized (mLock) { + if (mInstrumentClusterHelper == null) { + Log.w("mInstrumentClusterHelper still null, should wait until onBind", + new RuntimeException()); + } + return mInstrumentClusterHelper; + } + } + + /** + * Start Activity in fixed mode. + * + * <p>Activity launched in this way will stay visible across crash, package updatge + * or other Activity launch. So this should be carefully used for case like apps running + * in instrument cluster.</p> + * + * <p> Only one Activity can stay in this mode for a display and launching other Activity + * with this call means old one get out of the mode. Alternatively + * {@link #stopFixedActivityMode(int)} can be called to get the top activitgy out of this + * mode.</p> + * + * @param intent Should include specific {@code ComponentName}. + * @param options Should include target display. + * @param userId Target user id + * @return {@code true} if succeeded. {@code false} may mean the target component is not ready + * or available. Note that failure can happen during early boot-up stage even if the + * target Activity is in normal state and client should retry when it fails. Once it is + * successfully launched, car service will guarantee that it is running across crash or + * other events. + * + * @hide + */ + protected boolean startFixedActivityModeForDisplayAndUser(@NonNull Intent intent, + @NonNull ActivityOptions options, @UserIdInt int userId) { + IInstrumentClusterHelper helper = getClusterHelper(); + if (helper == null) { + return false; + } + try { + return helper.startFixedActivityModeForDisplayAndUser(intent, options.toBundle(), + userId); + } catch (RemoteException e) { + Log.w("Remote exception from car service", e); + // Probably car service will restart and rebind. So do nothing. + } + return false; + } + + + /** + * Stop fixed mode for top Activity in the display. Crashing or launching other Activity + * will not re-launch the top Activity any more. + * + * @hide + */ + protected void stopFixedActivityMode(int displayId) { + IInstrumentClusterHelper helper = getClusterHelper(); + if (helper == null) { + return; + } + try { + helper.stopFixedActivityMode(displayId); + } catch (RemoteException e) { + Log.w("Remote exception from car service, displayId:" + displayId, e); + // Probably car service will restart and rebind. So do nothing. + } + } + /** * Updates the cluster navigation activity by checking which activity to show (an activity of * the {@link #mNavContextOwner}). If not yet launched, it will do so. @@ -370,16 +468,19 @@ public abstract class InstrumentClusterRenderingService extends Service { @CallSuper @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println("**" + getClass().getSimpleName() + "**"); - writer.println("renderer binder: " + mRendererBinder); - if (mRendererBinder != null) { - writer.println("navigation renderer: " + mRendererBinder.mNavigationRenderer); - } - writer.println("navigation focus owner: " + getNavigationContextOwner()); - writer.println("activity options: " + mActivityOptions); - writer.println("activity state: " + mActivityState); - writer.println("current nav component: " + mNavigationComponent); - writer.println("current nav packages: " + getNavigationContextOwner().mPackageNames); + synchronized (mLock) { + writer.println("**" + getClass().getSimpleName() + "**"); + writer.println("renderer binder: " + mRendererBinder); + if (mRendererBinder != null) { + writer.println("navigation renderer: " + mRendererBinder.mNavigationRenderer); + } + writer.println("navigation focus owner: " + getNavigationContextOwner()); + writer.println("activity options: " + mActivityOptions); + writer.println("activity state: " + mActivityState); + writer.println("current nav component: " + mNavigationComponent); + writer.println("current nav packages: " + getNavigationContextOwner().mPackageNames); + writer.println("mInstrumentClusterHelper" + mInstrumentClusterHelper); + } } private class RendererBinder extends IInstrumentCluster.Stub { @@ -539,8 +640,18 @@ public abstract class InstrumentClusterRenderingService extends Service { } /** + * See {@link #getBitmap(Uri, int, int, float)} + * + * @throws IllegalArgumentException if {@code width} or {@code height} is not greater than 0. + */ + @Nullable + public Bitmap getBitmap(Uri uri, int width, int height) { + return getBitmap(uri, width, height, 1f); + } + + /** * Fetches a bitmap from the navigation context owner (application holding navigation focus) - * of the given width and height. The fetched bitmaps are cached. + * of the given width and height and off lane opacity. The fetched bitmaps are cached. * It returns null if: * <ul> * <li>there is no navigation context owner @@ -549,13 +660,17 @@ public abstract class InstrumentClusterRenderingService extends Service { * </ul> * This is a costly operation. Returned bitmaps should be fetched on a secondary thread. * - * @throws IllegalArgumentException if {@code width} or {@code height} is not greater than 0. + * @throws IllegalArgumentException if width, height <= 0, or 0 > offLanesAlpha > 1 + * @hide */ @Nullable - public Bitmap getBitmap(Uri uri, int width, int height) { + public Bitmap getBitmap(Uri uri, int width, int height, float offLanesAlpha) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Width and height must be > 0"); } + if (offLanesAlpha < 0 || offLanesAlpha > 1) { + throw new IllegalArgumentException("offLanesAlpha must be between [0, 1]"); + } try { ContextOwner contextOwner = getNavigationContextOwner(); @@ -567,6 +682,7 @@ public abstract class InstrumentClusterRenderingService extends Service { uri = uri.buildUpon() .appendQueryParameter(BITMAP_QUERY_WIDTH, String.valueOf(width)) .appendQueryParameter(BITMAP_QUERY_HEIGHT, String.valueOf(height)) + .appendQueryParameter(BITMAP_QUERY_OFFLANESALPHA, String.valueOf(offLanesAlpha)) .build(); String host = uri.getHost(); |