• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.server.am;
18 
19 import android.app.ActivityManagerInternal;
20 import android.app.ActivityOptions;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.IPackageDataObserver;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.Message;
31 import android.provider.Settings;
32 import android.text.BidiFormatter;
33 import android.util.Slog;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.WindowManager;
37 import android.widget.FrameLayout;
38 import android.widget.TextView;
39 
40 import java.util.List;
41 
42 import static com.android.server.am.ActivityManagerService.IS_USER_BUILD;
43 
44 final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListener {
45 
46     private final ActivityManagerService mService;
47     private final AppErrorResult mResult;
48     private final ProcessRecord mProc;
49     private final boolean mRepeating;
50     private final boolean mForeground;
51 
52     private CharSequence mName;
53 
54     static int CANT_SHOW = -1;
55     static int BACKGROUND_USER = -2;
56     static int ALREADY_SHOWING = -3;
57 
58     // Event 'what' codes
59     static final int FORCE_QUIT = 1;
60     static final int FORCE_QUIT_AND_REPORT = 2;
61     static final int RESTART = 3;
62     static final int MUTE = 5;
63     static final int TIMEOUT = 6;
64     static final int CANCEL = 7;
65 
66     // 5-minute timeout, then we automatically dismiss the crash dialog
67     static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
68 
AppErrorDialog(Context context, ActivityManagerService service, Data data)69     public AppErrorDialog(Context context, ActivityManagerService service, Data data) {
70         super(context);
71         Resources res = context.getResources();
72 
73         mService = service;
74         mProc = data.proc;
75         mResult = data.result;
76         mRepeating = data.repeating;
77         mForeground = data.task != null;
78         BidiFormatter bidi = BidiFormatter.getInstance();
79 
80         if ((mProc.pkgList.size() == 1) &&
81                 (mName = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
82             setTitle(res.getString(
83                     mRepeating ? com.android.internal.R.string.aerr_application_repeated
84                             : com.android.internal.R.string.aerr_application,
85                     bidi.unicodeWrap(mName.toString()),
86                     bidi.unicodeWrap(mProc.info.processName)));
87         } else {
88             mName = mProc.processName;
89             setTitle(res.getString(
90                     mRepeating ? com.android.internal.R.string.aerr_process_repeated
91                             : com.android.internal.R.string.aerr_process,
92                     bidi.unicodeWrap(mName.toString())));
93         }
94 
95         setCancelable(true);
96         setCancelMessage(mHandler.obtainMessage(CANCEL));
97 
98         WindowManager.LayoutParams attrs = getWindow().getAttributes();
99         attrs.setTitle("Application Error: " + mProc.info.processName);
100         attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
101                 | WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
102         getWindow().setAttributes(attrs);
103         if (mProc.persistent) {
104             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
105         }
106 
107         // After the timeout, pretend the user clicked the quit button
108         mHandler.sendMessageDelayed(
109                 mHandler.obtainMessage(TIMEOUT),
110                 DISMISS_TIMEOUT);
111     }
112 
113     @Override
onCreate(Bundle savedInstanceState)114     protected void onCreate(Bundle savedInstanceState) {
115         super.onCreate(savedInstanceState);
116         final FrameLayout frame = (FrameLayout) findViewById(android.R.id.custom);
117         final Context context = getContext();
118         LayoutInflater.from(context).inflate(
119                 com.android.internal.R.layout.app_error_dialog, frame, true);
120 
121         boolean hasRestart = !mRepeating && mForeground;
122         final boolean hasReceiver = mProc.errorReportReceiver != null;
123 
124         final TextView restart = (TextView) findViewById(com.android.internal.R.id.aerr_restart);
125         restart.setOnClickListener(this);
126         restart.setVisibility(hasRestart ? View.VISIBLE : View.GONE);
127         final TextView report = (TextView) findViewById(com.android.internal.R.id.aerr_report);
128         report.setOnClickListener(this);
129         report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE);
130         final TextView close = (TextView) findViewById(com.android.internal.R.id.aerr_close);
131         close.setVisibility(!hasRestart ? View.VISIBLE : View.GONE);
132         close.setOnClickListener(this);
133 
134         boolean showMute = !IS_USER_BUILD && Settings.Global.getInt(context.getContentResolver(),
135                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
136         final TextView mute = (TextView) findViewById(com.android.internal.R.id.aerr_mute);
137         mute.setOnClickListener(this);
138         mute.setVisibility(showMute ? View.VISIBLE : View.GONE);
139 
140         findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
141     }
142 
143     @Override
onStart()144     public void onStart() {
145         super.onStart();
146         getContext().registerReceiver(mReceiver,
147                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
148     }
149 
150     @Override
onStop()151     protected void onStop() {
152         super.onStop();
153         getContext().unregisterReceiver(mReceiver);
154     }
155 
156     private final Handler mHandler = new Handler() {
157         public void handleMessage(Message msg) {
158             final int result = msg.what;
159 
160             synchronized (mService) {
161                 if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
162                     mProc.crashDialog = null;
163                 }
164             }
165             mResult.set(result);
166 
167             // Make sure we don't have time timeout still hanging around.
168             removeMessages(TIMEOUT);
169 
170             dismiss();
171         }
172     };
173 
174     @Override
dismiss()175     public void dismiss() {
176         if (!mResult.mHasResult) {
177             // We are dismissing and the result has not been set...go ahead and set.
178             mResult.set(FORCE_QUIT);
179         }
180         super.dismiss();
181     }
182 
183     @Override
onClick(View v)184     public void onClick(View v) {
185         switch (v.getId()) {
186             case com.android.internal.R.id.aerr_restart:
187                 mHandler.obtainMessage(RESTART).sendToTarget();
188                 break;
189             case com.android.internal.R.id.aerr_report:
190                 mHandler.obtainMessage(FORCE_QUIT_AND_REPORT).sendToTarget();
191                 break;
192             case com.android.internal.R.id.aerr_close:
193                 mHandler.obtainMessage(FORCE_QUIT).sendToTarget();
194                 break;
195             case com.android.internal.R.id.aerr_mute:
196                 mHandler.obtainMessage(MUTE).sendToTarget();
197                 break;
198             default:
199                 break;
200         }
201     }
202 
203     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
204         @Override
205         public void onReceive(Context context, Intent intent) {
206             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
207                 cancel();
208             }
209         }
210     };
211 
212     static class Data {
213         AppErrorResult result;
214         TaskRecord task;
215         boolean repeating;
216         ProcessRecord proc;
217     }
218 }
219