1 /*
2  * Copyright 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 com.android.pump.activity;
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.widget.Toast;
25 
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.UiThread;
29 
30 import com.android.pump.util.Clog;
31 
32 @UiThread
33 // This class needs to inherit from Activity in order for Theme.Translucent to be applied correctly.
34 public class ActivityStarterActivity extends /* NOT AppCompatActivity !!! */ Activity {
35     private static final String TAG = Clog.tag(ActivityStarterActivity.class);
36 
37     private static final int REQUEST_CODE = 42;
38     private static final String EXTRA_INTENT =
39             "com.android.pump.activity.ActivityStarterActivity.EXTRA_INTENT";
40     private static final String EXTRA_OPTIONS =
41             "com.android.pump.activity.ActivityStarterActivity.EXTRA_OPTIONS";
42 
43     private boolean mApplicationCrashed;
44 
createStartIntent(@onNull Context context, @NonNull Intent intent, @Nullable Bundle options)45     public static @NonNull Intent createStartIntent(@NonNull Context context,
46             @NonNull Intent intent, @Nullable Bundle options) {
47         Intent wrapperIntent = new Intent(context, ActivityStarterActivity.class);
48         wrapperIntent.putExtra(EXTRA_INTENT, intent);
49         wrapperIntent.putExtra(EXTRA_OPTIONS, options);
50         return wrapperIntent;
51     }
52 
53     @Override
onCreate(@ullable Bundle savedInstanceState)54     protected void onCreate(@Nullable Bundle savedInstanceState) {
55         super.onCreate(savedInstanceState);
56 
57         if (savedInstanceState != null) {
58             // We're already waiting for the activity to finish, so don't start another instance.
59             mApplicationCrashed = true;
60             return;
61         }
62 
63         Intent intent = getIntent();
64         Intent startIntent = getExtraIntent(intent);
65         if (startIntent != null) {
66             try {
67                 Bundle options = intent.getParcelableExtra(EXTRA_OPTIONS);
68                 startActivityForResult(startIntent, REQUEST_CODE, options);
69                 mApplicationCrashed = true;
70             } catch (ActivityNotFoundException e) {
71                 Clog.w(TAG, "Failed to find activity for intent " + startIntent, e);
72 
73                 // TODO(b/123037263) I18n -- Move to resource
74                 cancel("Failed to find application");
75             } catch (SecurityException e) {
76                 Clog.w(TAG, "No permission to launch intent " + startIntent, e);
77 
78                 // TODO(b/123037263) I18n -- Move to resource
79                 cancel("No permission to launch application");
80             }
81         } else {
82             throw new IllegalArgumentException(
83                     "Couldn't find EXTRA_INTENT for activity starter activity");
84         }
85     }
86 
87     @Override
onDestroy()88     protected void onDestroy() {
89         super.onDestroy();
90 
91         if (!isFinishing()) {
92             // The system is temporarily killing us, so ignore for now.
93             return;
94         }
95 
96         if (mApplicationCrashed) {
97             Clog.w(TAG, "Activity crashed for intent " + getExtraIntent(getIntent()));
98 
99             // TODO(b/123037263) I18n -- Move to resource
100             Toast.makeText(this, "Tried to start an external application but it crashed.",
101                     Toast.LENGTH_SHORT).show();
102         }
103     }
104 
105     @Override
onActivityResult(int requestCode, int resultCode, Intent data)106     public void onActivityResult(int requestCode, int resultCode, Intent data) {
107         if (requestCode == REQUEST_CODE) {
108             mApplicationCrashed = false;
109             setResult(resultCode, data);
110             finish();
111         } else {
112             super.onActivityResult(requestCode, resultCode, data);
113         }
114     }
115 
getExtraIntent(@ullable Intent intent)116     private @Nullable Intent getExtraIntent(@Nullable Intent intent) {
117         return intent == null ? null : intent.getParcelableExtra(EXTRA_INTENT);
118     }
119 
cancel(@onNull CharSequence message)120     private void cancel(@NonNull CharSequence message) {
121         Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
122         setResult(Activity.RESULT_CANCELED);
123         finish();
124     }
125 }
126