• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Configuration;
23 import android.content.res.Resources;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.support.annotation.LayoutRes;
27 import android.support.car.Car;
28 import android.support.car.app.menu.CarDrawerActivity;
29 import android.support.car.input.CarInputManager;
30 import android.util.AttributeSet;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.Menu;
34 import android.view.MenuInflater;
35 import android.view.View;
36 import android.view.Window;
37 
38 /**
39  * A car specific activity class.  It allows an application to run on both "projected" and
40  * "native" platforms.  For the phone-only mode we only support media and messaging apps at this
41  * time. Please see our guides for writing
42  * <a href="https://developer.android.com/training/auto/index.html#media">media</a> and
43  * <a href="https://developer.android.com/training/auto/index.html#messaging">messaging</a> apps.
44  * <ul>
45  *     <li>
46  *         For "native" systems you'll additionally need to implement a
47  *         {@link CarProxyActivity} and add it to your application's manifest (see
48  *         {@link CarProxyActivity}) for details).
49  *     </li>
50  *     <li>
51  *         For "projected" systems you'll need to implement a
52  *         {@link com.google.android.apps.auto.sdk.activity.CarProxyProjectionActivityService}
53  *     </li>
54  * </ul>
55  *
56  * Applications wishing to write Android Auto applications will need to extend this class or one of
57  * it's sub classes. You'll most likely want to use {@link CarFragmentActivity} or
58  * {@link CarDrawerActivity} instead or this class as this one does not support fragments.
59  * <p/>
60  * This class has the look and feel of {@link Activity} however, it does not extend {@link Activity}
61  * or {@link Context}. Applications should use {@link #getContext()} to access the {@link Context}.
62  *
63  * @hide
64  */
65 public abstract class CarActivity {
66     private static final String TAG = "CarActivity";
67     public interface RequestPermissionsRequestCodeValidator {
validateRequestPermissionsRequestCode(int requestCode)68         public void validateRequestPermissionsRequestCode(int requestCode);
69     }
70     /**
71      * Interface to connect {@link CarActivity} to {@link android.app.Activity} or other app model.
72      * This interface provides utility for {@link CarActivity} to do things like manipulating view,
73      * handling menu, and etc.
74      */
75     public abstract static class Proxy {
setIntent(Intent i)76         abstract public void setIntent(Intent i);
setContentView(View view)77         abstract public void setContentView(View view);
setContentView(int layoutResID)78         abstract public void setContentView(int layoutResID);
getResources()79         abstract public Resources getResources();
findViewById(int id)80         abstract public View findViewById(int id);
getLayoutInflater()81         abstract public LayoutInflater getLayoutInflater();
getIntent()82         abstract public Intent getIntent();
finish()83         abstract public void finish();
getCarInputManager()84         abstract public CarInputManager getCarInputManager();
isFinishing()85         abstract public boolean isFinishing();
getMenuInflater()86         abstract public MenuInflater getMenuInflater();
finishAfterTransition()87         abstract public void finishAfterTransition();
getWindow()88         abstract public Window getWindow();
setResult(int resultCode)89         abstract public void setResult(int resultCode);
setResult(int resultCode, Intent data)90         abstract public void setResult(int resultCode, Intent data);
91 
requestPermissions(String[] permissions, int requestCode)92         public void requestPermissions(String[] permissions, int requestCode) {
93             Log.w(TAG, "No support for requestPermissions");
94         }
shouldShowRequestPermissionRationale(String permission)95         public boolean shouldShowRequestPermissionRationale(String permission) {
96             Log.w(TAG, "No support for shouldShowRequestPermissionRationale");
97             return false;
98         }
startActivityForResult(Intent intent, int requestCode)99         public void startActivityForResult(Intent intent, int requestCode) {
100             Log.w(TAG, "No support for startActivityForResult");
101         };
102     }
103 
104     /** @hide */
105     public static final int CMD_ON_CREATE = 0;
106     /** @hide */
107     public static final int CMD_ON_START = 1;
108     /** @hide */
109     public static final int CMD_ON_RESTART = 2;
110     /** @hide */
111     public static final int CMD_ON_RESUME = 3;
112     /** @hide */
113     public static final int CMD_ON_PAUSE = 4;
114     /** @hide */
115     public static final int CMD_ON_STOP = 5;
116     /** @hide */
117     public static final int CMD_ON_DESTROY = 6;
118     /** @hide */
119     public static final int CMD_ON_BACK_PRESSED = 7;
120     /** @hide */
121     public static final int CMD_ON_SAVE_INSTANCE_STATE = 8;
122     /** @hide */
123     public static final int CMD_ON_RESTORE_INSTANCE_STATE = 9;
124     /** @hide */
125     public static final int CMD_ON_CONFIG_CHANGED = 10;
126     /** @hide */
127     public static final int CMD_ON_REQUEST_PERMISSIONS_RESULT = 11;
128     /** @hide */
129     public static final int CMD_ON_NEW_INTENT = 12;
130     /** @hide */
131     public static final int CMD_ON_ACTIVITY_RESULT = 13;
132     /** @hide */
133     public static final int CMD_ON_POST_RESUME = 14;
134     /** @hide */
135     public static final int CMD_ON_LOW_MEMORY = 15;
136 
137     private final Proxy mProxy;
138     private final Context mContext;
139     private final Car mCar;
140     private final Handler mHandler = new Handler();
141 
CarActivity(Proxy proxy, Context context, Car car)142     public CarActivity(Proxy proxy, Context context, Car car) {
143         mProxy = proxy;
144         mContext = context;
145         mCar = car;
146     }
147 
148     /**
149      * Returns a standard app {@link Context} object since this class does not extend {@link
150      * Context} link {@link Activity} does.
151      */
getContext()152     public Context getContext() {
153         return mContext;
154     }
155 
156     /**
157      * Returns an instance of the {@link Car} object.  This is the main entry point to interact
158      * with the car and it's data.
159      *
160      * <p/>
161      * Note: For "native" platform uses cases you'll need to construct the CarProxy activity with
162      * the createCar boolean set to true if you want to use the getCar() method.
163      * <pre>
164      * {@code
165      *
166      *   class FooProxyActivity extends CarProxyActivity {
167      *     public FooProxyActivity() {
168      *       super(FooActivity.class, true);
169      *     }
170      *   }
171      * }
172      * </pre>
173      *
174      * "Projected" use cases will create a Car instance by default.
175      *
176      * @throws IllegalStateException if the Car object is not available.
177      */
getCar()178     public Car getCar() {
179         if (mCar == null) {
180             throw new IllegalStateException("The default Car is not available. You can either " +
181                     "create a Car by yourself or indicate the need of the default Car in the " +
182                     "CarProxyActivity's constructor.");
183         }
184         return mCar;
185     }
186 
187     /**
188      * Returns the input manager for car activities.
189      */
getInputManager()190     public CarInputManager getInputManager() {
191         return mProxy.getCarInputManager();
192     }
193 
194     /**
195      * See {@link Activity#getResources()}.
196      */
getResources()197     public Resources getResources() {
198         return mProxy.getResources();
199     }
200 
201     /**
202      * See {@link Activity#setContentView(View)}.
203      */
setContentView(View view)204     public void setContentView(View view) {
205         mProxy.setContentView(view);
206     }
207 
208     /**
209      * See {@link Activity#setContentView(int)}.
210      */
setContentView(@ayoutRes int resourceId)211     public void setContentView(@LayoutRes int resourceId) {
212         mProxy.setContentView(resourceId);
213     }
214 
215     /**
216      * See {@link Activity#getLayoutInflater()}.
217      */
getLayoutInflater()218     public LayoutInflater getLayoutInflater() {
219         return mProxy.getLayoutInflater();
220     }
221 
222     /**
223      * See {@link Activity#getIntent()}
224      */
getIntent()225     public Intent getIntent() {
226         return mProxy.getIntent();
227     }
228 
229     /**
230      * See {@link Activity#setResult(int)}  }
231      */
setResult(int resultCode)232     public void setResult(int resultCode){
233         mProxy.setResult(resultCode);
234     }
235 
236 
237     /**
238      * See {@link Activity#setResult(int, Intent)}  }
239      */
setResult(int resultCode, Intent data)240     public void setResult(int resultCode, Intent data) {
241         mProxy.setResult(resultCode, data);
242     }
243 
244     /**
245      * See {@link Activity#findViewById(int)}  }
246      */
findViewById(int id)247     public View findViewById(int id) {
248         return mProxy.findViewById(id);
249     }
250 
251     /**
252      * See {@link Activity#finish()}
253      */
finish()254     public void finish() {
255         mProxy.finish();
256     }
257 
258     /**
259      * See {@link Activity#isFinishing()}
260      */
isFinishing()261     public boolean isFinishing() {
262         return mProxy.isFinishing();
263     }
264 
265     /**
266      * See {@link Activity#shouldShowRequestPermissionRationale(String)}
267      */
shouldShowRequestPermissionRationale(String permission)268     public boolean shouldShowRequestPermissionRationale(String permission) {
269         return mProxy.shouldShowRequestPermissionRationale(permission);
270     }
271 
272     /**
273      * See {@link Activity#requestPermissions(String[], int)}
274      */
requestPermissions(String[] permissions, int requestCode)275     public void requestPermissions(String[] permissions, int requestCode) {
276         if (this instanceof RequestPermissionsRequestCodeValidator) {
277             ((RequestPermissionsRequestCodeValidator) this)
278                     .validateRequestPermissionsRequestCode(requestCode);
279         }
280         mProxy.requestPermissions(permissions, requestCode);
281     }
282 
283     /**
284      * See {@link Activity#setIntent(Intent)}
285      */
setIntent(Intent i)286     public void setIntent(Intent i) {
287         mProxy.setIntent(i);
288     }
289 
290     /**
291      * See {@link Activity#finishAfterTransition()}
292      */
finishAfterTransition()293     public void finishAfterTransition() {
294         mProxy.finishAfterTransition();
295     }
296 
297     /**
298      * See {@link Activity#getMenuInflater()}
299      */
getMenuInflater()300     public MenuInflater getMenuInflater() {
301         return mProxy.getMenuInflater();
302     }
303 
304     /**
305      * See {@link Activity#getWindow()}
306      */
getWindow()307     public Window getWindow() {
308         return mProxy.getWindow();
309     }
310 
311     /**
312      * See {@link Activity#getLastNonConfigurationInstance()}
313      */
getLastNonConfigurationInstance()314     public Object getLastNonConfigurationInstance() {
315         return null;
316     }
317 
318     /**
319      * See {@link Activity#startActivityForResult(Intent, int)}
320      */
startActivityForResult(Intent intent, int requestCode)321     public void startActivityForResult(Intent intent, int requestCode) {
322         mProxy.startActivityForResult(intent, requestCode);
323     }
324 
325     /**
326      * See {@link Activity#runOnUiThread(Runnable)}
327      */
runOnUiThread(Runnable runnable)328     public void runOnUiThread(Runnable runnable) {
329         if (Thread.currentThread() == mHandler.getLooper().getThread()) {
330             runnable.run();
331         } else {
332             mHandler.post(runnable);
333         }
334     }
335 
336     /** @hide */
dispatchCmd(int cmd, Object... args)337     public void dispatchCmd(int cmd, Object... args) {
338 
339         switch (cmd) {
340             case CMD_ON_CREATE:
341                 assertArgsLength(1, args);
342                 onCreate((Bundle) args[0]);
343                 break;
344             case CMD_ON_START:
345                 onStart();
346                 break;
347             case CMD_ON_RESTART:
348                 onRestart();
349                 break;
350             case CMD_ON_RESUME:
351                 onResume();
352                 break;
353             case CMD_ON_POST_RESUME:
354                 onPostResume();
355                 break;
356             case CMD_ON_PAUSE:
357                 onPause();
358                 break;
359             case CMD_ON_STOP:
360                 onStop();
361                 break;
362             case CMD_ON_DESTROY:
363                 onDestroy();
364                 break;
365             case CMD_ON_BACK_PRESSED:
366                 onBackPressed();
367                 break;
368             case CMD_ON_SAVE_INSTANCE_STATE:
369                 assertArgsLength(1, args);
370                 onSaveInstanceState((Bundle) args[0]);
371                 break;
372             case CMD_ON_RESTORE_INSTANCE_STATE:
373                 assertArgsLength(1, args);
374                 onRestoreInstanceState((Bundle) args[0]);
375                 break;
376             case CMD_ON_REQUEST_PERMISSIONS_RESULT:
377                 assertArgsLength(3, args);
378                 onRequestPermissionsResult(((Integer) args[0]).intValue(),
379                         (String[]) args[1], convertArray((Integer[]) args[2]));
380                 break;
381             case CMD_ON_CONFIG_CHANGED:
382                 assertArgsLength(1, args);
383                 onConfigurationChanged((Configuration) args[0]);
384                 break;
385             case CMD_ON_NEW_INTENT:
386                 assertArgsLength(1, args);
387                 onNewIntent((Intent) args[0]);
388                 break;
389             case CMD_ON_ACTIVITY_RESULT:
390                 assertArgsLength(3, args);
391                 onActivityResult(((Integer) args[0]).intValue(), ((Integer) args[1]).intValue(),
392                         (Intent) args[2]);
393                 break;
394             case CMD_ON_LOW_MEMORY:
395                 onLowMemory();
396                 break;
397             default:
398                 throw new RuntimeException("Unknown dispatch cmd for CarActivity, " + cmd);
399         }
400 
401     }
402 
403     /**
404      * See {@link Activity#onCreate(Bundle)}
405      */
onCreate(Bundle savedInstanceState)406     protected void onCreate(Bundle savedInstanceState) {
407     }
408 
409     /**
410      * See {@link Activity#onStart()}
411      */
onStart()412     protected void onStart() {
413     }
414 
415     /**
416      * See {@link Activity#onRestart()}
417      */
onRestart()418     protected void onRestart() {
419     }
420 
421     /**
422      * See {@link Activity#onResume()}
423      */
onResume()424     protected void onResume() {
425     }
426 
427     /**
428      * See {@link Activity#onPostResume()}
429      */
onPostResume()430     protected void onPostResume() {
431     }
432 
433     /**
434      * See {@link Activity#onPause()}
435      */
onPause()436     protected void onPause() {
437     }
438 
439     /**
440      * See {@link Activity#onStop()}
441      */
onStop()442     protected void onStop() {
443     }
444 
445     /**
446      * See {@link Activity#onDestroy()}
447      */
onDestroy()448     protected void onDestroy() {
449     }
450 
451     /**
452      * See {@link Activity#onRestoreInstanceState(Bundle)}
453      */
onRestoreInstanceState(Bundle savedInstanceState)454     protected void onRestoreInstanceState(Bundle savedInstanceState) {
455     }
456 
457     /**
458      * See {@link Activity#onSaveInstanceState(Bundle)}
459      */
onSaveInstanceState(Bundle outState)460     protected void onSaveInstanceState(Bundle outState) {
461     }
462 
463     /**
464      * See {@link Activity#onBackPressed()}
465      */
onBackPressed()466     protected void onBackPressed() {
467     }
468 
469     /**
470      * See {@link Activity#onConfigurationChanged(Configuration)}
471      */
onConfigurationChanged(Configuration newConfig)472     protected void onConfigurationChanged(Configuration newConfig) {
473     }
474 
475     /**
476      * See {@link Activity#onNewIntent(Intent)}
477      */
onNewIntent(Intent intent)478     protected void onNewIntent(Intent intent) {
479     }
480 
481     /**
482      * See {@link Activity#onRequestPermissionsResult(int, String[], int[])}
483      */
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)484     public void onRequestPermissionsResult(int requestCode, String[] permissions,
485             int[] grantResults) {
486     }
487 
488     /**
489      * See {@link Activity#onActivityResult(int, int, Intent)}
490      */
onActivityResult(int requestCode, int resultCode, Intent data)491     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
492     }
493 
494     /**
495      * See {@link Activity#onRetainNonConfigurationInstance()}
496      */
onRetainNonConfigurationInstance()497     public Object onRetainNonConfigurationInstance() {
498         return null;
499     }
500 
501     // TODO: hook up panel menu if it's needed in any apps.
502     /**
503      * Currently always returns false.
504      * See {@link Activity#onCreatePanelMenu(int, Menu)}
505      */
onCreatePanelMenu(int featureId, Menu menu)506     public boolean onCreatePanelMenu(int featureId, Menu menu) {
507         return false; // default menu will not be displayed.
508     }
509 
510     /**
511      * See {@link Activity#onCreateView(View, String, Context, AttributeSet)}
512      */
onCreateView(View parent, String name, Context context, AttributeSet attrs)513     public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
514         // CarFragmentActivity can override this to dispatch onCreateView to fragments
515         return null;
516     }
517 
518     /**
519      * See {@link Activity#onLowMemory()}
520      */
onLowMemory()521     public void onLowMemory() {
522     }
523 
assertArgsLength(int length, Object... args)524     private void assertArgsLength(int length, Object... args) {
525         if (args == null || args.length != length) {
526             throw new IllegalArgumentException(
527                     String.format("Wrong number of parameters. Expected: %d Actual: %d",
528                             length, args == null ? 0 : args.length));
529         }
530     }
531 
convertArray(Integer[] array)532     private static int[] convertArray(Integer[] array) {
533         int[] results = new int[array.length];
534         for(int i = 0; i < results.length; i++) {
535             results[i] = array[i].intValue();
536         }
537         return results;
538     }
539 }
540