1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.car.projection; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.app.ActivityOptions; 24 import android.car.builtin.app.ActivityManagerHelper; 25 import android.content.ComponentName; 26 import android.os.Bundle; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * This class holds OEM customization for projection receiver app. It is created by Car Service. 33 * 34 * @hide 35 */ 36 @SystemApi 37 public class ProjectionOptions { 38 private static final String KEY_PREFIX = "android.car.projection."; 39 40 /** Immersive full screen mode (all system bars are hidden) */ 41 public static final int UI_MODE_FULL_SCREEN = 0; 42 43 /** Show status and navigation bars. */ 44 public static final int UI_MODE_BLENDED = 1; 45 46 private static final int UI_MODE_DEFAULT = UI_MODE_FULL_SCREEN; 47 48 /** @hide */ 49 @IntDef({UI_MODE_FULL_SCREEN, UI_MODE_BLENDED}) 50 @Retention(RetentionPolicy.SOURCE) 51 public @interface ProjectionUiMode {} 52 53 /** Indicates that head unit didn't specify information about access point mode. This value 54 * can only be seen on Android SDK 31 and below. */ 55 public static final int AP_MODE_NOT_SPECIFIED = 0; 56 57 /** Projection access point was created such that it may provide Internet access. */ 58 public static final int AP_MODE_TETHERED = 1; 59 60 /** 61 * Projection access point was created as local-only hotspot, without Internet access and the 62 * credentials will be auto-generated for every access point initialization. 63 */ 64 public static final int AP_MODE_LOHS_DYNAMIC_CREDENTIALS = 2; 65 66 /** 67 * Projection access point was created as local-only hotspot, without Internet access and the 68 * credentials will persist reboots. Credentials still can be reseted by user or app request. 69 */ 70 public static final int AP_MODE_LOHS_STATIC_CREDENTIALS = 3; 71 72 /** @hide */ 73 @IntDef({AP_MODE_NOT_SPECIFIED, AP_MODE_TETHERED, AP_MODE_LOHS_DYNAMIC_CREDENTIALS, 74 AP_MODE_LOHS_STATIC_CREDENTIALS}) 75 @Retention(RetentionPolicy.SOURCE) 76 public @interface ProjectionAccessPointMode {} 77 78 private static final String KEY_ACTIVITY_OPTIONS = KEY_PREFIX + "activityOptions"; 79 private static final String KEY_UI_MODE = KEY_PREFIX + "systemUiFlags"; 80 private static final String KEY_CONSENT_ACTIVITY = KEY_PREFIX + "consentActivity"; 81 private static final String KEY_ACCESS_POINT_MODE = KEY_PREFIX + "ap_mode"; 82 83 private final ActivityOptions mActivityOptions; 84 private final int mUiMode; 85 private final ComponentName mConsentActivity; 86 private final int mApMode; 87 88 /** 89 * Creates new instance for given {@code Bundle} 90 * 91 * @param bundle contains OEM specific information 92 */ ProjectionOptions(Bundle bundle)93 public ProjectionOptions(Bundle bundle) { 94 Bundle activityOptionsBundle = bundle.getBundle(KEY_ACTIVITY_OPTIONS); 95 mActivityOptions = activityOptionsBundle != null 96 ? ActivityManagerHelper.createActivityOptions(activityOptionsBundle) : null; 97 mUiMode = bundle.getInt(KEY_UI_MODE, UI_MODE_DEFAULT); 98 mConsentActivity = bundle.getParcelable(KEY_CONSENT_ACTIVITY); 99 mApMode = bundle.getInt(KEY_ACCESS_POINT_MODE, AP_MODE_NOT_SPECIFIED); 100 } 101 ProjectionOptions(Builder builder)102 private ProjectionOptions(Builder builder) { 103 mActivityOptions = builder.mActivityOptions; 104 mUiMode = builder.mUiMode; 105 mConsentActivity = builder.mConsentActivity; 106 mApMode = builder.mApMode; 107 } 108 109 /** 110 * Returns combination of flags from View.SYSTEM_UI_FLAG_* which will be used by projection 111 * receiver app during rendering. 112 */ getUiMode()113 public @ProjectionUiMode int getUiMode() { 114 return mUiMode; 115 } 116 117 /** 118 * Returns projection access point mode. 119 * 120 * <p>The result could be one of the following values: 121 * <ul> 122 * <li>{@link #AP_MODE_NOT_SPECIFIED}</li> 123 * <li>{@link #AP_MODE_TETHERED}</li> 124 * <li>{@link #AP_MODE_LOHS_DYNAMIC_CREDENTIALS}</li> 125 * <li>{@link #AP_MODE_LOHS_STATIC_CREDENTIALS}</li> 126 * </ul> 127 */ getProjectionAccessPointMode()128 public @ProjectionAccessPointMode int getProjectionAccessPointMode() { 129 return mApMode; 130 } 131 132 /** 133 * Returns {@link ActivityOptions} that needs to be applied when launching projection activity 134 */ getActivityOptions()135 public @Nullable ActivityOptions getActivityOptions() { 136 return mActivityOptions; 137 } 138 139 /** 140 * Returns package/activity name of the consent activity provided by OEM which needs to be shown 141 * for all mobile devices unless user accepted the consent. 142 * 143 * <p>If the method returns null then consent dialog should not be shown. 144 */ getConsentActivity()145 public @Nullable ComponentName getConsentActivity() { 146 return mConsentActivity; 147 } 148 149 /** Converts current object to {@link Bundle} */ toBundle()150 public @NonNull Bundle toBundle() { 151 Bundle bundle = new Bundle(); 152 if (mActivityOptions != null) { 153 bundle.putBundle(KEY_ACTIVITY_OPTIONS, mActivityOptions.toBundle()); 154 } 155 bundle.putParcelable(KEY_CONSENT_ACTIVITY, mConsentActivity); 156 if (mUiMode != UI_MODE_DEFAULT) { 157 bundle.putInt(KEY_UI_MODE, mUiMode); 158 } 159 bundle.putInt(KEY_ACCESS_POINT_MODE, mApMode); 160 return bundle; 161 } 162 163 /** @hide */ builder()164 public static Builder builder() { 165 return new Builder(); 166 } 167 168 /** @hide */ 169 public static class Builder { 170 private ActivityOptions mActivityOptions; 171 private int mUiMode = UI_MODE_DEFAULT; 172 private ComponentName mConsentActivity; 173 private int mApMode = AP_MODE_NOT_SPECIFIED; 174 175 /** Sets {@link ActivityOptions} to launch projection activity. */ setProjectionActivityOptions(ActivityOptions activityOptions)176 public Builder setProjectionActivityOptions(ActivityOptions activityOptions) { 177 mActivityOptions = activityOptions; 178 return this; 179 } 180 181 /** Set UI for projection activity. It can be one of {@code UI_MODE_*} constants. */ setUiMode(@rojectionUiMode int uiMode)182 public Builder setUiMode(@ProjectionUiMode int uiMode) { 183 mUiMode = uiMode; 184 return this; 185 } 186 187 /** Sets consent activity which will be shown before starting projection. */ setConsentActivity(ComponentName consentActivity)188 public Builder setConsentActivity(ComponentName consentActivity) { 189 mConsentActivity = consentActivity; 190 return this; 191 } 192 193 /** Sets projection access point mode */ setAccessPointMode(@rojectionAccessPointMode int accessPointMode)194 public Builder setAccessPointMode(@ProjectionAccessPointMode int accessPointMode) { 195 this.mApMode = accessPointMode; 196 return this; 197 } 198 199 /** Creates an instance of {@link android.car.projection.ProjectionOptions} */ build()200 public ProjectionOptions build() { 201 return new ProjectionOptions(this); 202 } 203 } 204 205 /** @hide */ 206 @Override toString()207 public String toString() { 208 return toBundle().toString(); 209 } 210 } 211