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