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 com.android.tv;
18 
19 import android.app.Activity;
20 import android.content.ActivityNotFoundException;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.util.Log;
25 
26 /**
27  * An activity to launch a new activity.
28  *
29  * <p>In the case when {@link MainActivity} starts a new activity using {@link
30  * Activity#startActivity} or {@link Activity#startActivityForResult}, TV app is terminated if the
31  * new activity crashes. That's because the {@link android.app.ActivityManager} terminates the
32  * activity which is just below the crashed activity in the activity stack. To avoid this, we need
33  * to locate an additional activity between these activities in the activity stack.
34  */
35 public class LauncherActivity extends Activity {
36     private static final String TAG = "LauncherActivity";
37 
38     public static final String ERROR_MESSAGE = "com.android.tv.LauncherActivity.ErrorMessage";
39 
40     private static final int REQUEST_CODE_DEFAULT = 0;
41     private static final int REQUEST_START_ACTIVITY = 100;
42 
43     private static final String EXTRA_INTENT = "com.android.tv.LauncherActivity.INTENT";
44     private static final String EXTRA_REQUEST_RESULT =
45             "com.android.tv.LauncherActivity.REQUEST_RESULT";
46 
47     /** Starts an activity by calling {@link Activity#startActivity}. */
startActivitySafe(Activity baseActivity, Intent intentToLaunch)48     public static void startActivitySafe(Activity baseActivity, Intent intentToLaunch) {
49         // To avoid the app termination when the new activity crashes, LauncherActivity should be
50         // started by calling startActivityForResult().
51         baseActivity.startActivityForResult(
52                 createIntent(baseActivity, intentToLaunch, false), REQUEST_CODE_DEFAULT);
53     }
54 
createIntent( Context context, Intent intentToLaunch, boolean requestResult)55     private static Intent createIntent(
56             Context context, Intent intentToLaunch, boolean requestResult) {
57         Intent intent = new Intent(context, LauncherActivity.class);
58         intent.putExtra(EXTRA_INTENT, intentToLaunch);
59         if (requestResult) {
60             intent.putExtra(EXTRA_REQUEST_RESULT, true);
61         }
62         return intent;
63     }
64 
65     @Override
onCreate(Bundle savedInstanceState)66     public void onCreate(Bundle savedInstanceState) {
67         super.onCreate(savedInstanceState);
68         // We should launch the new activity in onCreate rather than in onStart.
69         // That's because it is not guaranteed that onStart is called only once.
70         Intent intent = getIntent().getParcelableExtra(EXTRA_INTENT);
71         boolean requestResult = getIntent().getBooleanExtra(EXTRA_REQUEST_RESULT, false);
72         try {
73             if (requestResult) {
74                 startActivityForResult(intent, REQUEST_START_ACTIVITY);
75             } else {
76                 startActivity(intent);
77                 setResult(Activity.RESULT_OK);
78                 finish();
79             }
80         } catch (ActivityNotFoundException e) {
81             Log.w(TAG, "Activity not found for " + intent);
82             intent.putExtra(ERROR_MESSAGE, getResources().getString(R.string.msg_missing_app));
83             setResult(Activity.RESULT_CANCELED, intent);
84             finish();
85         }
86     }
87 
88     @Override
onActivityResult(int requestCode, int resultCode, Intent data)89     public void onActivityResult(int requestCode, int resultCode, Intent data) {
90         setResult(resultCode, data);
91         finish();
92     }
93 }
94