1 /* 2 * Copyright (C) 2015 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.support.car.app; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.os.Bundle; 24 import android.os.Handler; 25 import android.support.annotation.LayoutRes; 26 import android.support.car.Car; 27 import android.support.car.input.CarInputManager; 28 import android.util.AttributeSet; 29 import android.util.Log; 30 import android.view.LayoutInflater; 31 import android.view.Menu; 32 import android.view.MenuInflater; 33 import android.view.View; 34 import android.view.Window; 35 36 /** 37 * Abstraction for car UI. Car applications should implement this for car UI. 38 * The API looks like {@link android.app.Activity}, and behaves like one, but it is neither 39 * android {@link android.app.Activity} nor {@link android.app.Context}. 40 * Applications should use {@link #getContext()} to get necessary {@link android.app.Context}. 41 */ 42 public abstract class CarActivity { 43 private static final String TAG = "CarActivity"; 44 public interface RequestPermissionsRequestCodeValidator { validateRequestPermissionsRequestCode(int requestCode)45 public void validateRequestPermissionsRequestCode(int requestCode); 46 } 47 /** 48 * Interface to connect {@link CarActivity} to {@link android.app.Activity} or other app model. 49 * This interface provides utility for {@link CarActivity} to do things like manipulating view, 50 * handling menu, and etc. 51 */ 52 public abstract static class Proxy { setIntent(Intent i)53 abstract public void setIntent(Intent i); setContentView(View view)54 abstract public void setContentView(View view); setContentView(int layoutResID)55 abstract public void setContentView(int layoutResID); getResources()56 abstract public Resources getResources(); findViewById(int id)57 abstract public View findViewById(int id); getLayoutInflater()58 abstract public LayoutInflater getLayoutInflater(); getIntent()59 abstract public Intent getIntent(); finish()60 abstract public void finish(); getCarInputManager()61 abstract public CarInputManager getCarInputManager(); isFinishing()62 abstract public boolean isFinishing(); getMenuInflater()63 abstract public MenuInflater getMenuInflater(); finishAfterTransition()64 abstract public void finishAfterTransition(); getWindow()65 abstract public Window getWindow(); setResult(int resultCode)66 abstract public void setResult(int resultCode); setResult(int resultCode, Intent data)67 abstract public void setResult(int resultCode, Intent data); 68 requestPermissions(String[] permissions, int requestCode)69 public void requestPermissions(String[] permissions, int requestCode) { 70 Log.w(TAG, "No support for requestPermissions"); 71 } shouldShowRequestPermissionRationale(String permission)72 public boolean shouldShowRequestPermissionRationale(String permission) { 73 Log.w(TAG, "No support for shouldShowRequestPermissionRationale"); 74 return false; 75 } startActivityForResult(Intent intent, int requestCode)76 public void startActivityForResult(Intent intent, int requestCode) { 77 Log.w(TAG, "No support for startActivityForResult"); 78 }; 79 } 80 81 /** @hide */ 82 public static final int CMD_ON_CREATE = 0; 83 /** @hide */ 84 public static final int CMD_ON_START = 1; 85 /** @hide */ 86 public static final int CMD_ON_RESTART = 2; 87 /** @hide */ 88 public static final int CMD_ON_RESUME = 3; 89 /** @hide */ 90 public static final int CMD_ON_PAUSE = 4; 91 /** @hide */ 92 public static final int CMD_ON_STOP = 5; 93 /** @hide */ 94 public static final int CMD_ON_DESTROY = 6; 95 /** @hide */ 96 public static final int CMD_ON_BACK_PRESSED = 7; 97 /** @hide */ 98 public static final int CMD_ON_SAVE_INSTANCE_STATE = 8; 99 /** @hide */ 100 public static final int CMD_ON_RESTORE_INSTANCE_STATE = 9; 101 /** @hide */ 102 public static final int CMD_ON_CONFIG_CHANGED = 10; 103 /** @hide */ 104 public static final int CMD_ON_REQUEST_PERMISSIONS_RESULT = 11; 105 /** @hide */ 106 public static final int CMD_ON_NEW_INTENT = 12; 107 /** @hide */ 108 public static final int CMD_ON_ACTIVITY_RESULT = 13; 109 /** @hide */ 110 public static final int CMD_ON_POST_RESUME = 14; 111 /** @hide */ 112 public static final int CMD_ON_LOW_MEMORY = 15; 113 114 private final Proxy mProxy; 115 private final Context mContext; 116 private final Car mCar; 117 private final Handler mHandler = new Handler(); 118 CarActivity(Proxy proxy, Context context, Car car)119 public CarActivity(Proxy proxy, Context context, Car car) { 120 mProxy = proxy; 121 mContext = context; 122 mCar = car; 123 } 124 getContext()125 public Context getContext() { 126 return mContext; 127 } 128 getCar()129 public Car getCar() { 130 if (mCar == null) { 131 throw new IllegalStateException("The default Car is not available. You can either " + 132 "create a Car by yourself or indicate the need of the default Car in the " + 133 "CarProxyActivity's constructor."); 134 } 135 return mCar; 136 } 137 getResources()138 public Resources getResources() { 139 return mProxy.getResources(); 140 } 141 setContentView(View view)142 public void setContentView(View view) { 143 mProxy.setContentView(view); 144 } 145 setContentView(@ayoutRes int resourceId)146 public void setContentView(@LayoutRes int resourceId) { 147 mProxy.setContentView(resourceId); 148 } 149 getLayoutInflater()150 public LayoutInflater getLayoutInflater() { 151 return mProxy.getLayoutInflater(); 152 } 153 getIntent()154 public Intent getIntent() { 155 return mProxy.getIntent(); 156 } 157 setResult(int resultCode)158 public void setResult(int resultCode){ 159 mProxy.setResult(resultCode); 160 } 161 setResult(int resultCode, Intent data)162 public void setResult(int resultCode, Intent data) { 163 mProxy.setResult(resultCode, data); 164 } 165 getInputManager()166 public CarInputManager getInputManager() { 167 return mProxy.getCarInputManager(); 168 } 169 findViewById(int id)170 public View findViewById(int id) { 171 return mProxy.findViewById(id); 172 } 173 finish()174 public void finish() { 175 mProxy.finish(); 176 } 177 isFinishing()178 public boolean isFinishing() { 179 return mProxy.isFinishing(); 180 } 181 shouldShowRequestPermissionRationale(String permission)182 public boolean shouldShowRequestPermissionRationale(String permission) { 183 return mProxy.shouldShowRequestPermissionRationale(permission); 184 } 185 requestPermissions(String[] permissions, int requestCode)186 public void requestPermissions(String[] permissions, int requestCode) { 187 if (this instanceof RequestPermissionsRequestCodeValidator) { 188 ((RequestPermissionsRequestCodeValidator) this) 189 .validateRequestPermissionsRequestCode(requestCode); 190 } 191 mProxy.requestPermissions(permissions, requestCode); 192 } 193 setIntent(Intent i)194 public void setIntent(Intent i) { 195 mProxy.setIntent(i); 196 } 197 finishAfterTransition()198 public void finishAfterTransition() { 199 mProxy.finishAfterTransition(); 200 } 201 getMenuInflater()202 public MenuInflater getMenuInflater() { 203 return mProxy.getMenuInflater(); 204 } 205 getWindow()206 public Window getWindow() { 207 return mProxy.getWindow(); 208 } 209 getLastNonConfigurationInstance()210 public Object getLastNonConfigurationInstance() { 211 return null; 212 } 213 startActivityForResult(Intent intent, int requestCode)214 public void startActivityForResult(Intent intent, int requestCode) { 215 mProxy.startActivityForResult(intent, requestCode); 216 } 217 runOnUiThread(Runnable runnable)218 public void runOnUiThread(Runnable runnable) { 219 if (Thread.currentThread() == mHandler.getLooper().getThread()) { 220 runnable.run(); 221 } else { 222 mHandler.post(runnable); 223 } 224 } 225 226 /** @hide */ dispatchCmd(int cmd, Object... args)227 public void dispatchCmd(int cmd, Object... args) { 228 229 switch (cmd) { 230 case CMD_ON_CREATE: 231 assertArgsLength(1, args); 232 onCreate((Bundle) args[0]); 233 break; 234 case CMD_ON_START: 235 onStart(); 236 break; 237 case CMD_ON_RESTART: 238 onRestart(); 239 break; 240 case CMD_ON_RESUME: 241 onResume(); 242 break; 243 case CMD_ON_POST_RESUME: 244 onPostResume(); 245 break; 246 case CMD_ON_PAUSE: 247 onPause(); 248 break; 249 case CMD_ON_STOP: 250 onStop(); 251 break; 252 case CMD_ON_DESTROY: 253 onDestroy(); 254 break; 255 case CMD_ON_BACK_PRESSED: 256 onBackPressed(); 257 break; 258 case CMD_ON_SAVE_INSTANCE_STATE: 259 assertArgsLength(1, args); 260 onSaveInstanceState((Bundle) args[0]); 261 break; 262 case CMD_ON_RESTORE_INSTANCE_STATE: 263 assertArgsLength(1, args); 264 onRestoreInstanceState((Bundle) args[0]); 265 break; 266 case CMD_ON_REQUEST_PERMISSIONS_RESULT: 267 assertArgsLength(3, args); 268 onRequestPermissionsResult(((Integer) args[0]).intValue(), 269 (String[]) args[1], convertArray((Integer[]) args[2])); 270 break; 271 case CMD_ON_CONFIG_CHANGED: 272 assertArgsLength(1, args); 273 onConfigurationChanged((Configuration) args[0]); 274 break; 275 case CMD_ON_NEW_INTENT: 276 assertArgsLength(1, args); 277 onNewIntent((Intent) args[0]); 278 break; 279 case CMD_ON_ACTIVITY_RESULT: 280 assertArgsLength(3, args); 281 onActivityResult(((Integer) args[0]).intValue(), ((Integer) args[1]).intValue(), 282 (Intent) args[2]); 283 break; 284 case CMD_ON_LOW_MEMORY: 285 onLowMemory(); 286 break; 287 default: 288 throw new RuntimeException("Unknown dispatch cmd for CarActivity, " + cmd); 289 } 290 291 } 292 onCreate(Bundle savedInstanceState)293 protected void onCreate(Bundle savedInstanceState) { 294 } 295 onStart()296 protected void onStart() { 297 } 298 onRestart()299 protected void onRestart() { 300 } 301 onResume()302 protected void onResume() { 303 } 304 onPostResume()305 protected void onPostResume() { 306 } 307 onPause()308 protected void onPause() { 309 } 310 onStop()311 protected void onStop() { 312 } 313 onDestroy()314 protected void onDestroy() { 315 } 316 onRestoreInstanceState(Bundle savedInstanceState)317 protected void onRestoreInstanceState(Bundle savedInstanceState) { 318 } 319 onSaveInstanceState(Bundle outState)320 protected void onSaveInstanceState(Bundle outState) { 321 } 322 onBackPressed()323 protected void onBackPressed() { 324 } 325 onConfigurationChanged(Configuration newConfig)326 protected void onConfigurationChanged(Configuration newConfig) { 327 } 328 onNewIntent(Intent intent)329 protected void onNewIntent(Intent intent) { 330 } 331 onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)332 public void onRequestPermissionsResult(int requestCode, String[] permissions, 333 int[] grantResults) { 334 } 335 onActivityResult(int requestCode, int resultCode, Intent data)336 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 337 } 338 onRetainNonConfigurationInstance()339 public Object onRetainNonConfigurationInstance() { 340 return null; 341 } 342 343 // TODO: hook up panel menu if it's needed in any apps. onCreatePanelMenu(int featureId, Menu menu)344 public boolean onCreatePanelMenu(int featureId, Menu menu) { 345 return false; // default menu will not be displayed. 346 } 347 onCreateView(View parent, String name, Context context, AttributeSet attrs)348 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { 349 // CarFragmentActivity can override this to dispatch onCreateView to fragments 350 return null; 351 } 352 onLowMemory()353 public void onLowMemory() { 354 } 355 assertArgsLength(int length, Object... args)356 private void assertArgsLength(int length, Object... args) { 357 if (args == null || args.length != length) { 358 throw new IllegalArgumentException( 359 String.format("Wrong number of parameters. Expected: %d Actual: %d", 360 length, args == null ? 0 : args.length)); 361 } 362 } 363 convertArray(Integer[] array)364 private static int[] convertArray(Integer[] array) { 365 int[] results = new int[array.length]; 366 for(int i = 0; i < results.length; i++) { 367 results[i] = array[i].intValue(); 368 } 369 return results; 370 } 371 } 372