• Home
  • History
  • Annotate
  • 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 = 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 = findViewById(com.android.internal.R.id.aerr_restart);
118         restart.setOnClickListener(this);
119         restart.setVisibility(hasRestart ? View.VISIBLE : View.GONE);
120         final TextView report = findViewById(com.android.internal.R.id.aerr_report);
121         report.setOnClickListener(this);
122         report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE);
123         final TextView close = 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 = 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             setResult(msg.what);
152             dismiss();
153         }
154     };
155 
156     @Override
dismiss()157     public void dismiss() {
158         if (!mResult.mHasResult) {
159             // We are dismissing and the result has not been set...go ahead and set.
160             setResult(FORCE_QUIT);
161         }
162         super.dismiss();
163     }
164 
setResult(int result)165     private void setResult(int result) {
166         synchronized (mService) {
167             if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
168                 mProc.crashDialog = null;
169             }
170         }
171         mResult.set(result);
172 
173         // Make sure we don't have time timeout still hanging around.
174         mHandler.removeMessages(TIMEOUT);
175     }
176 
177     @Override
onClick(View v)178     public void onClick(View v) {
179         switch (v.getId()) {
180             case com.android.internal.R.id.aerr_restart:
181                 mHandler.obtainMessage(RESTART).sendToTarget();
182                 break;
183             case com.android.internal.R.id.aerr_report:
184                 mHandler.obtainMessage(FORCE_QUIT_AND_REPORT).sendToTarget();
185                 break;
186             case com.android.internal.R.id.aerr_close:
187                 mHandler.obtainMessage(FORCE_QUIT).sendToTarget();
188                 break;
189             case com.android.internal.R.id.aerr_mute:
190                 mHandler.obtainMessage(MUTE).sendToTarget();
191                 break;
192             default:
193                 break;
194         }
195     }
196 
197     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
198         @Override
199         public void onReceive(Context context, Intent intent) {
200             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
201                 cancel();
202             }
203         }
204     };
205 
206     static class Data {
207         AppErrorResult result;
208         TaskRecord task;
209         boolean repeating;
210         ProcessRecord proc;
211         boolean isRestartableForService;
212     }
213 }
214