public class

TestCarContext

extends CarContext

 java.lang.Object

↳ContextWrapper

androidx.car.app.CarContext

↳androidx.car.app.testing.TestCarContext

Gradle dependencies

compile group: 'androidx.car.app', name: 'app-testing', version: '1.7.0-beta01'

  • groupId: androidx.car.app
  • artifactId: app-testing
  • version: 1.7.0-beta01

Artifact androidx.car.app:app-testing:1.7.0-beta01 it located at Google repository (https://maven.google.com/)

Overview

The CarContext that is used for testing.

This class will return the test version of car services for tracking calls during testing.

It also allows retrieving the car services already cast to the testing class by calling TestCarContext.getCarService(Class) with the class name of the test services:

 testCarContext.getCarService(TestAppManager.class)
 testCarContext.getCarService(TestNavigationManager.class)
 testCarContext.getCarService(TestScreenManager.class)

Allows retrieving all s sent via CarContext.startCarApp(Intent).

Summary

Fields
from CarContextACTION_NAVIGATE, APP_SERVICE, CAR_SERVICE, CONSTRAINT_SERVICE, EXTRA_START_CAR_APP_BINDER_KEY, HARDWARE_SERVICE, MEDIA_PLAYBACK_SERVICE, NAVIGATION_SERVICE, SCREEN_SERVICE, SUGGESTION_SERVICE
Methods
public static TestCarContextcreateCarContext(Context testContext)

Creates a TestCarContext to use for testing.

public voidfinishCarApp()

Requests to finish the car app.

public java.lang.ObjectgetCarService(java.lang.Class<java.lang.Object> serviceClass)

Returns a car service by class.

public java.lang.ObjectgetCarService(java.lang.String name)

Provides a car service by name.

public FakeHostgetFakeHost()

Retrieve the FakeHost being used.

public TestCarContext.PermissionRequestInfogetLastPermissionRequestInfo()

Returns a TestCarContext.PermissionRequestInfo including the information with the last call made to CarContext.requestPermissions(List, OnRequestPermissionsListener), or null if no call was made.

public TestLifecycleOwnergetLifecycleOwner()

Returns the TestLifecycleOwner that is used for this CarContext.

public java.util.List<Intent>getStartCarAppIntents()

Returns all s sent via CarContext.startCarApp(Intent).

public IStartCarAppgetStartCarAppStub()

Returns the IStartCarApp instance that is being used by this CarContext.

public booleanhasCalledFinishCarApp()

Verifies if CarContext.finishCarApp() has been called.

public voidoverrideCarService(java.lang.Class<Manager> serviceClass, java.lang.Object service)

Sets the service as the service instance for the given serviceClass.

public voidrequestPermissions(java.util.List<java.lang.String> permissions, java.util.concurrent.Executor executor, OnRequestPermissionsListener listener)

Requests the provided permissions from the user.

public voidreset()

Resets the values tracked by this TestCarContext.

public voidstartCarApp(Intent intent)

Starts a car app on the car screen.

from CarContextcreate, getCallingComponent, getCarAppApiLevel, getCarServiceName, getHostInfo, getOnBackPressedDispatcher, isDarkMode, requestPermissions, setCarAppResult, setCarHost, startCarApp, updateHandshakeInfo
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public void reset()

Resets the values tracked by this TestCarContext.

public java.lang.Object getCarService(java.lang.Class<java.lang.Object> serviceClass)

Returns a car service by class.

See CarContext.getCarService(String) for a list of the supported car services.

This method should not be called until the of the context's Session is at least .

Parameters:

serviceClass: the class of the requested service

public java.lang.Object getCarService(java.lang.String name)

Provides a car service by name.

The class of the returned object varies by the requested name.

Currently supported car services, and their respective classes, are:

CarContext.APP_SERVICE
An AppManager for communication between the app and the host.
CarContext.NAVIGATION_SERVICE
A NavigationManager for management of navigation updates.
CarContext.SCREEN_SERVICE
A ScreenManager for management of Screens.
CarContext.CONSTRAINT_SERVICE
A ConstraintManager for management of content limits.
CarContext.HARDWARE_SERVICE
A CarHardwareManager for interacting with car hardware (e.g. sensors) data.
CarContext.SUGGESTION_SERVICE
A SuggestionManager for posting Suggestions.

This method should not be called until the of the context's Session is at least .

Parameters:

name: The name of the car service requested. This should be one of CarContext.APP_SERVICE, CarContext.NAVIGATION_SERVICE or CarContext.SCREEN_SERVICE

Returns:

The car service instance

public void startCarApp(Intent intent)

Starts a car app on the car screen.

The target application will get the via Session.onCreateScreen(Intent) or Session.onNewIntent(Intent).

Supported s:

An to navigate.
The action must be CarContext.ACTION_NAVIGATE.
The data URI scheme must be either a latitude,longitude pair, or a + separated string query as follows:
1) "geo:12.345,14.8767" for a latitude, longitude pair.
2) "geo:0,0?q=123+Main+St,+Seattle,+WA+98101" for an address.
3) "geo:0,0?q=a+place+name" for a place to search for.
An to make a phone call.
The must be created as defined here.
An to start this app in the car.
The component name of the intent must be the one for the CarAppService that contains this CarContext. If the component name is for a different component, the method will throw a java.lang.SecurityException.

This method should not be called until the of the context's Session is at least .

Parameters:

intent: the to send to the target application

public void finishCarApp()

Requests to finish the car app.

Call this when your app is done and should be closed. The Session corresponding to this CarContext will become State.DESTROYED.

At some point after this call, the OS will destroy your CarAppService.

This method should not be called until the of the context's Session is at least .

public void requestPermissions(java.util.List<java.lang.String> permissions, java.util.concurrent.Executor executor, OnRequestPermissionsListener listener)

Requests the provided permissions from the user.

When the result is available, the listener provided will be called using the java.util.concurrent.Executor provided.

This method should be called using a ParkedOnlyOnClickListener.

If this method is called while the host deems it is unsafe (for example, when the user is driving), the permission(s) will not be requested from the user.

If the Session is destroyed before the user accepts or rejects the permissions, the callback will not be executed.

Platform Considerations

Using this method allows the app to work across all platforms supported by the library with the same API (e.g. Android Auto on mobile devices and Android Automotive OS on native car heads unit). On a mobile platform, this method will start an activity that will display the platform's permissions UI over it. You can choose to not use this method and instead implement your own activity and code to request the permissions in that platform. On Automotive OS however, distraction-optimized activities other than CarAppActivity are not allowed and may be rejected during app submission. See CarAppActivity for more details.

Parameters:

permissions: the runtime permissions to request from the user
executor: the executor that will be used for calling the callback provided
listener: listener that will be notified when the user takes action on the permission request

public static TestCarContext createCarContext(Context testContext)

Creates a TestCarContext to use for testing.

public java.util.List<Intent> getStartCarAppIntents()

Returns all s sent via CarContext.startCarApp(Intent).

The s are stored in the order of when they were sent, where the first intent in the list, is the first intent sent.

The results will be stored until TestCarContext.reset() is called.

public TestCarContext.PermissionRequestInfo getLastPermissionRequestInfo()

Returns a TestCarContext.PermissionRequestInfo including the information with the last call made to CarContext.requestPermissions(List, OnRequestPermissionsListener), or null if no call was made.

public boolean hasCalledFinishCarApp()

Verifies if CarContext.finishCarApp() has been called.

public FakeHost getFakeHost()

Retrieve the FakeHost being used.

public void overrideCarService(java.lang.Class<Manager> serviceClass, java.lang.Object service)

Sets the service as the service instance for the given serviceClass.

This can be used to mock a car service.

Internal use only.

public TestLifecycleOwner getLifecycleOwner()

Returns the TestLifecycleOwner that is used for this CarContext.

public IStartCarApp getStartCarAppStub()

Returns the IStartCarApp instance that is being used by this CarContext.

Source

/*
 * Copyright 2020 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 androidx.car.app.testing;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import static java.util.Objects.requireNonNull;

import android.content.Context;
import android.content.Intent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.car.app.CarContext;
import androidx.car.app.HostDispatcher;
import androidx.car.app.ICarHost;
import androidx.car.app.IStartCarApp;
import androidx.car.app.OnRequestPermissionsListener;
import androidx.car.app.managers.Manager;
import androidx.car.app.testing.navigation.TestNavigationManager;
import androidx.car.app.utils.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * The {@link CarContext} that is used for testing.
 *
 * <p>This class will return the test version of car services for tracking calls during testing.
 *
 * <p>It also allows retrieving the car services already cast to the testing class by calling {@link
 * #getCarService} with the class name of the test services:
 *
 * <pre>{@code testCarContext.getCarService(TestAppManager.class)}</pre>
 *
 * <pre>{@code testCarContext.getCarService(TestNavigationManager.class)}</pre>
 *
 * <pre>{@code testCarContext.getCarService(TestScreenManager.class)}</pre>
 *
 * <p>Allows retrieving all {@link Intent}s sent via {@link CarContext#startCarApp(Intent)}.
 */
public class TestCarContext extends CarContext {
    private final Map<String, Object> mOverriddenService = new HashMap<>();
    private final IStartCarApp mStartCarApp = new StartCarAppStub();

    private final FakeHost mFakeHost;
    private final TestLifecycleOwner mTestLifecycleOwner;
    private final TestAppManager mTestAppManager;
    private final TestNavigationManager mTestNavigationManager;
    private final TestScreenManager mTestScreenManager;

    final List<Intent> mStartCarAppIntents = new ArrayList<>();
    @Nullable
    private PermissionRequestInfo mLastPermissionRequestInfo = null;
    private boolean mHasCalledFinishCarApp;

    /** Resets the values tracked by this {@link TestCarContext}. */
    public void reset() {
        mStartCarAppIntents.clear();
    }

    @NonNull
    @Override
    public <T> T getCarService(@NonNull Class<T> serviceClass) {
        String serviceName;

        if (serviceClass.isInstance(mTestAppManager)) {
            serviceName = APP_SERVICE;
        } else if (serviceClass.isInstance(mTestNavigationManager)) {
            serviceName = NAVIGATION_SERVICE;
        } else if (serviceClass.isInstance(mTestScreenManager)) {
            serviceName = SCREEN_SERVICE;
        } else {
            serviceName = getCarServiceName(serviceClass);
        }

        return requireNonNull(serviceClass.cast(getCarService(serviceName)));
    }

    @Override
    @NonNull
    public Object getCarService(@NonNull String name) {
        Object service = mOverriddenService.get(name);
        if (service != null) {
            return service;
        }

        switch (name) {
            case CarContext.APP_SERVICE:
                return mTestAppManager;
            case CarContext.NAVIGATION_SERVICE:
                return mTestNavigationManager;
            case CarContext.SCREEN_SERVICE:
                return mTestScreenManager;
            default:
                // Fall out
        }
        return super.getCarService(name);
    }

    @Override
    public void startCarApp(@NonNull Intent intent) {
        mStartCarAppIntents.add(intent);
    }

    @Override
    public void finishCarApp() {
        mHasCalledFinishCarApp = true;
    }

    @Override
    public void requestPermissions(@NonNull List<String> permissions, @NonNull Executor executor,
            @NonNull OnRequestPermissionsListener listener) {
        mLastPermissionRequestInfo = new PermissionRequestInfo(requireNonNull(permissions),
                requireNonNull(listener));
        super.requestPermissions(permissions, executor, listener);
    }

    /**
     * Creates a {@link TestCarContext} to use for testing.
     *
     * @throws NullPointerException if {@code testContext} is null
     */
    @NonNull
    public static TestCarContext createCarContext(@NonNull Context testContext) {
        requireNonNull(testContext);

        TestCarContext carContext = new TestCarContext(new TestLifecycleOwner(),
                new HostDispatcher());
        carContext.attachBaseContext(testContext);
        carContext.setCarHost(carContext.mFakeHost.getCarHost());

        return carContext;
    }

    /**
     * Returns all {@link Intent}s sent via {@link CarContext#startCarApp(Intent)}.
     *
     * <p>The {@link Intent}s are stored in the order of when they were sent, where the first
     * intent in the list, is the first intent sent.
     *
     * <p>The results will be stored until {@link #reset} is called.
     */
    @NonNull
    public List<Intent> getStartCarAppIntents() {
        return CollectionUtils.unmodifiableCopy(mStartCarAppIntents);
    }

    /**
     * Returns a {@link PermissionRequestInfo} including the information with the last call made to
     * {@link CarContext#requestPermissions}, or {@code null} if no call was made.
     */
    @Nullable
    public PermissionRequestInfo getLastPermissionRequestInfo() {
        return mLastPermissionRequestInfo;
    }

    /** Verifies if {@link CarContext#finishCarApp} has been called. */
    public boolean hasCalledFinishCarApp() {
        return mHasCalledFinishCarApp;
    }

    /**
     * Retrieve the {@link FakeHost} being used.
     */
    @NonNull
    public FakeHost getFakeHost() {
        return mFakeHost;
    }

    /**
     * Sets the {@code service} as the service instance for the given {@code serviceClass}.
     *
     * <p>This can be used to mock a car service.
     *
     * <p>Internal use only.
     *
     * @throws NullPointerException if either {@code serviceClass} or {@code service} are {@code
     *                              null}
     */
    @RestrictTo(LIBRARY_GROUP)
    public void overrideCarService(@NonNull Class<? extends Manager> serviceClass,
            @NonNull Object service) {
        requireNonNull(service);
        requireNonNull(serviceClass);

        String serviceName = getCarServiceName(serviceClass);
        mOverriddenService.put(serviceName, service);
    }

    /**
     * Returns the {@link TestLifecycleOwner} that is used for this CarContext.
     *
     */
    @RestrictTo(LIBRARY_GROUP)
    @NonNull
    public TestLifecycleOwner getLifecycleOwner() {
        return mTestLifecycleOwner;
    }

    /**
     * Returns the {@link IStartCarApp} instance that is being used by this CarContext.
     *
     */
    @RestrictTo(LIBRARY_GROUP)
    @NonNull
    public IStartCarApp getStartCarAppStub() {
        return mStartCarApp;
    }

    ICarHost getCarHostStub() {
        return mFakeHost.getCarHost();
    }

    /** Testing version of the start car app binder for notifications. */
    class StartCarAppStub extends IStartCarApp.Stub {
        @Override
        public void startCarApp(Intent intent) {
            mStartCarAppIntents.add(intent);
        }
    }

    /**
     * A representation of a permission request including the permissions that were requested as
     * well as the callback provided.
     */
    public static class PermissionRequestInfo {
        private final List<String> mPermissionsRequested;
        private final OnRequestPermissionsListener mListener;

        @SuppressWarnings("ExecutorRegistration")
        PermissionRequestInfo(List<String> permissionsRequested,
                OnRequestPermissionsListener callback) {
            mPermissionsRequested = requireNonNull(permissionsRequested);
            mListener = requireNonNull(callback);
        }

        /**
         * Returns the listener that was provided in the permission request.
         */
        @NonNull
        public OnRequestPermissionsListener getListener() {
            return mListener;
        }

        /**
         * Returns the permissions that were requested.
         */
        @NonNull
        public List<String> getPermissionsRequested() {
            return mPermissionsRequested;
        }
    }

    private TestCarContext(TestLifecycleOwner testLifecycleOwner, HostDispatcher hostDispatcher) {
        super(testLifecycleOwner.mRegistry, hostDispatcher);

        this.mFakeHost = new FakeHost(this);
        this.mTestLifecycleOwner = testLifecycleOwner;
        this.mTestAppManager = new TestAppManager(this, hostDispatcher);
        this.mTestNavigationManager = new TestNavigationManager(this, hostDispatcher);
        this.mTestScreenManager = new TestScreenManager(this);
    }
}