1/*
2 * Copyright (C) 2011 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 */
16package com.android.commands.sendbug;
17
18import android.accounts.Account;
19import android.accounts.IAccountManager;
20import android.app.ActivityManagerNative;
21import android.app.IActivityManager;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.IPackageManager;
25import android.content.pm.ResolveInfo;
26import android.net.Uri;
27import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.os.SystemProperties;
30import android.os.UserHandle;
31import android.util.Log;
32
33import java.io.File;
34import java.util.ArrayList;
35import java.util.List;
36import java.util.regex.Pattern;
37
38public class SendBug {
39
40    private static final String LOG_TAG = SendBug.class.getSimpleName();
41    private static final Pattern EMAIL_REGEX = Pattern.compile(
42            "^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
43    private static final String SEND_BUG_INTENT_ACTION = "android.testing.SEND_BUG";
44
45    public static void main(String[] args) {
46        if (args.length == 1) {
47            new SendBug().run(args[0]);
48        } else if (args.length == 2) {
49            new SendBug().run(args[0], args[1]);
50        }
51    }
52
53    private void run(String bugreportPath) {
54        run(bugreportPath, null);
55    }
56
57    private void run(String bugreportPath, String screenShotPath) {
58        final File bugreport = new File(bugreportPath);
59        File screenShot = null;
60        if (screenShotPath != null) {
61            screenShot = new File(screenShotPath);
62        }
63        final Uri bugreportUri = Uri.fromFile(bugreport);
64        // todo (aalbert): investigate adding a screenshot to BugReporter
65        Intent intent = tryBugReporter(bugreportUri);
66        if (intent == null) {
67            final Uri screenshotUri = screenShot != null
68                    ? Uri.fromFile(screenShot) : null;
69            intent = getSendMailIntent(bugreportUri, screenshotUri);
70        }
71        if (intent != null) {
72            final IActivityManager am = ActivityManagerNative.getDefault();
73            if (am == null) {
74                Log.e(LOG_TAG, "Cannot get ActivityManager, is the system running?");
75                return;
76            }
77            try {
78                am.startActivityAsUser(null, intent, intent.getType(), null, null, 0, 0,
79                        null, null, null, UserHandle.USER_CURRENT);
80            } catch (RemoteException e) {
81                // ignore
82            }
83        } else {
84            Log.w(LOG_TAG, "Cannot find account to send bugreport, local path: "
85                    + bugreportPath);
86        }
87    }
88
89    private Intent tryBugReporter(Uri bugreportUri) {
90        final Intent intent = new Intent(SEND_BUG_INTENT_ACTION);
91        intent.setData(bugreportUri);
92        final IPackageManager pm = IPackageManager.Stub.asInterface(
93                ServiceManager.getService("package"));
94        if (pm == null) {
95            Log.e(LOG_TAG, "Cannot get PackageManager, is the system running?");
96            return null;
97        }
98        final List<ResolveInfo> results;
99        try {
100            results = pm.queryIntentActivities(intent, null, 0, 0);
101        } catch (RemoteException e) {
102            return null;
103        }
104        if (results != null && results.size() > 0) {
105            final ResolveInfo info = results.get(0);
106            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107            intent.setClassName(info.activityInfo.applicationInfo.packageName,
108                    info.activityInfo.name);
109            return intent;
110        } else {
111            return null;
112        }
113    }
114
115    private Intent getSendMailIntent(Uri bugreportUri, Uri screenshotUri) {
116        final Account sendToAccount = findSendToAccount();
117        final Intent intent = new Intent(Intent.ACTION_SEND);
118        intent.addCategory(Intent.CATEGORY_DEFAULT);
119        intent.setType("application/octet-stream");
120        intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
121        final StringBuilder sb = new StringBuilder();
122        sb.append(SystemProperties.get("ro.build.description"));
123        sb.append("\n(Sent from BugMailer)");
124        intent.putExtra(Intent.EXTRA_TEXT, (CharSequence)sb);
125        if (screenshotUri != null) {
126            final ArrayList<Uri> attachments = new ArrayList<Uri>();
127            attachments.add(bugreportUri);
128            attachments.add(screenshotUri);
129            intent.setAction(Intent.ACTION_SEND_MULTIPLE);
130            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
131        } else {
132            intent.putExtra(Intent.EXTRA_STREAM, bugreportUri);
133        }
134        if (sendToAccount != null) {
135            intent.putExtra(Intent.EXTRA_EMAIL, new String[]{sendToAccount.name});
136            return intent;
137        }
138        return null;
139    }
140
141    private Account findSendToAccount() {
142        final IAccountManager accountManager = IAccountManager.Stub.asInterface(ServiceManager
143                .getService(Context.ACCOUNT_SERVICE));
144        if (accountManager == null) {
145            Log.e(LOG_TAG, "Cannot get AccountManager, is the system running?");
146            return null;
147        }
148        Account[] accounts = null;
149        Account foundAccount = null;
150        String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
151        if (!preferredDomain.startsWith("@")) {
152            preferredDomain = "@" + preferredDomain;
153        }
154        try {
155            accounts = accountManager.getAccounts(null);
156        } catch (RemoteException e) {
157            // ignore
158        }
159        if (accounts != null) {
160            for (Account account : accounts) {
161                if (EMAIL_REGEX.matcher(account.name).matches()) {
162                    if (!preferredDomain.isEmpty()) {
163                        // if we have a preferred domain and it matches, return; otherwise keep
164                        // looking
165                        if (account.name.endsWith(preferredDomain)) {
166                            return account;
167                        } else {
168                            foundAccount = account;
169                        }
170                        // if we don't have a preferred domain, just return since it looks like
171                        // an email address
172                    } else {
173                        return account;
174                    }
175                }
176            }
177        }
178        return foundAccount;
179    }
180}
181