/* * 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; import static androidx.car.app.utils.LogTags.TAG; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.RestrictTo; import androidx.annotation.StringDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Defines all constants for permissions that a car app can use. */ public final class CarAppPermission { /** * Defines which permissions are ones defined by the car app library. * */ @RestrictTo(RestrictTo.Scope.LIBRARY) @StringDef(value = {ACCESS_SURFACE, NAVIGATION_TEMPLATES}) @Retention(RetentionPolicy.SOURCE) public @interface LibraryPermission { } /** * Permission that apps can use to get access to a canvas surface. * *

This surface can be used for drawing custom content like navigation apps can use it to * draw a map. */ public static final String ACCESS_SURFACE = "androidx.car.app.ACCESS_SURFACE"; /** * Permission that apps can use to get access to the navigation templates of the car app * library. * *

This permission should only be declared by apps that belong to one of the categories that * allow using the navigation templates. See * the * documentation for the list of such categories. An app not in one of those categories * requesting this permission may be rejected upon submission to the Play Store. See * {@link CarAppService} for how to declare your app's category. */ public static final String NAVIGATION_TEMPLATES = "androidx.car.app.NAVIGATION_TEMPLATES"; /** * Permission that apps can use to get access to templates that show a map such as * {@link androidx.car.app.model.PlaceListMapTemplate}. Templates used by navigation apps that * draw their own maps * (e.g. {@link androidx.car.app.navigation.model.PlaceListNavigationTemplate}) don't require * this permission. * *

This permission should only be declared by apps that belong to one of the categories that * allow using the map templates. See * the * documentation for the list of such categories. An app not in one of those categories * requesting this permission may be rejected upon submission to the Play Store. See * {@link CarAppService} for how to declare your app's category. */ public static final String MAP_TEMPLATES = "androidx.car.app.MAP_TEMPLATES"; /** * Checks that the car app has the given {@code permission} granted. * * @throws SecurityException if the app does not have a required permission granted */ public static void checkHasPermission(@NonNull Context context, @NonNull String permission) { if (context.getPackageManager().checkPermission(permission, context.getPackageName()) == PackageManager.PERMISSION_GRANTED) { return; } throw new SecurityException( "The car app does not have the required permission: " + permission); } /** * Checks that the car app has declared the required library {@code permission}. * *

In contrast to {@link #checkHasPermission}, this method will validate that the app has at * least declared the permission requested. * * @throws SecurityException if the app does not have the required permission declared */ @SuppressWarnings("deprecation") public static void checkHasLibraryPermission( @NonNull Context context, @NonNull @LibraryPermission String permission) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Checking to see if the car app requested the required library permission: " + permission); } try { checkHasPermission(context, permission); return; } catch (SecurityException e) { // Do nothing, we use a fallback for library permissions. } // Fallback for devices where permissions may not be granted by the system if the app // was installed before the host is installed. try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo( context.getPackageName(), PackageManager.GET_PERMISSIONS); if (packageInfo.requestedPermissions != null) { for (String requestedPermission : packageInfo.requestedPermissions) { if (requestedPermission.equals(permission)) { return; } } } } catch (NameNotFoundException e) { Log.e(TAG, "Package name not found on the system: " + context.getPackageName(), e); } throw new SecurityException( "The car app does not have a required permission: " + permission); } private CarAppPermission() { } }