18c658e058446ad69fb056b2160340d708582b9eeGuang Zhu/*
28c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * Copyright (C) 2011 The Android Open Source Project
38c658e058446ad69fb056b2160340d708582b9eeGuang Zhu *
48c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
58c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * you may not use this file except in compliance with the License.
68c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * You may obtain a copy of the License at
78c658e058446ad69fb056b2160340d708582b9eeGuang Zhu *
88c658e058446ad69fb056b2160340d708582b9eeGuang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
98c658e058446ad69fb056b2160340d708582b9eeGuang Zhu *
108c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * Unless required by applicable law or agreed to in writing, software
118c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
128c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * See the License for the specific language governing permissions and
148c658e058446ad69fb056b2160340d708582b9eeGuang Zhu * limitations under the License.
158c658e058446ad69fb056b2160340d708582b9eeGuang Zhu */
168c658e058446ad69fb056b2160340d708582b9eeGuang Zhupackage com.android.commands.sendbug;
178c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
188c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.accounts.Account;
198c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.accounts.IAccountManager;
208c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.app.ActivityManagerNative;
218c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.app.IActivityManager;
228c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.content.Context;
238c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.content.Intent;
24d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhuimport android.content.pm.IPackageManager;
25d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhuimport android.content.pm.ResolveInfo;
268c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.net.Uri;
278c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.os.RemoteException;
288c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.os.ServiceManager;
298c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport android.os.SystemProperties;
30fa98203c441d00d374349ce35c0c7ba2f38cc53aDianne Hackbornimport android.os.UserHandle;
319ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhuimport android.util.Log;
328c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
338c658e058446ad69fb056b2160340d708582b9eeGuang Zhuimport java.io.File;
3401cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albertimport java.util.ArrayList;
35d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhuimport java.util.List;
369ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhuimport java.util.regex.Pattern;
378c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
388c658e058446ad69fb056b2160340d708582b9eeGuang Zhupublic class SendBug {
398c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
409ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu    private static final String LOG_TAG = SendBug.class.getSimpleName();
419ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu    private static final Pattern EMAIL_REGEX = Pattern.compile(
429ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu            "^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
43d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu    private static final String SEND_BUG_INTENT_ACTION = "android.testing.SEND_BUG";
448c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
458c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    public static void main(String[] args) {
468beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        if (args.length == 1) {
478c658e058446ad69fb056b2160340d708582b9eeGuang Zhu            new SendBug().run(args[0]);
488beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        } else if (args.length == 2) {
498beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu            new SendBug().run(args[0], args[1]);
508c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        }
518c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    }
528c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
538c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    private void run(String bugreportPath) {
548beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        run(bugreportPath, null);
558beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu    }
568beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu
578beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu    private void run(String bugreportPath, String screenShotPath) {
5801cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final File bugreport = new File(bugreportPath);
598beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        File screenShot = null;
608beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        if (screenShotPath != null) {
618beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu            screenShot = new File(screenShotPath);
628beb39758fe046fc19ebee7317949b9ba7ee97ddGuang Zhu        }
636186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        final Uri bugreportUri = Uri.fromFile(bugreport);
646186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        // todo (aalbert): investigate adding a screenshot to BugReporter
656186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        Intent intent = tryBugReporter(bugreportUri);
666186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        if (intent == null) {
676186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey            final Uri screenshotUri = screenShot != null
686186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey                    ? Uri.fromFile(screenShot) : null;
696186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey            intent = getSendMailIntent(bugreportUri, screenshotUri);
706186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        }
716186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        if (intent != null) {
72818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            final IActivityManager am = ActivityManagerNative.getDefault();
73818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            if (am == null) {
74818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu                Log.e(LOG_TAG, "Cannot get ActivityManager, is the system running?");
75818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu                return;
76818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            }
776186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey            try {
78fa98203c441d00d374349ce35c0c7ba2f38cc53aDianne Hackborn                am.startActivityAsUser(null, intent, intent.getType(), null, null, 0, 0,
79fa98203c441d00d374349ce35c0c7ba2f38cc53aDianne Hackborn                        null, null, null, UserHandle.USER_CURRENT);
806186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey            } catch (RemoteException e) {
816186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey                // ignore
828c658e058446ad69fb056b2160340d708582b9eeGuang Zhu            }
836186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey        } else {
846186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey            Log.w(LOG_TAG, "Cannot find account to send bugreport, local path: "
856186a9cb55dae698f048616bb82887565d5779dfJeff Sharkey                    + bugreportPath);
868c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        }
878c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    }
888c658e058446ad69fb056b2160340d708582b9eeGuang Zhu
89d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu    private Intent tryBugReporter(Uri bugreportUri) {
9001cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final Intent intent = new Intent(SEND_BUG_INTENT_ACTION);
91d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        intent.setData(bugreportUri);
92818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        final IPackageManager pm = IPackageManager.Stub.asInterface(
93d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu                ServiceManager.getService("package"));
94818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        if (pm == null) {
95818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            Log.e(LOG_TAG, "Cannot get PackageManager, is the system running?");
96818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            return null;
97818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        }
98818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        final List<ResolveInfo> results;
99818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        try {
100818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            results = pm.queryIntentActivities(intent, null, 0, 0);
101818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        } catch (RemoteException e) {
102818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            return null;
103818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        }
104818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        if (results != null && results.size() > 0) {
105818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            final ResolveInfo info = results.get(0);
106818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            intent.setClassName(info.activityInfo.applicationInfo.packageName,
108818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu                    info.activityInfo.name);
109818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            return intent;
110818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        } else {
111818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            return null;
112d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        }
113d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu    }
114d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu
11501cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert    private Intent getSendMailIntent(Uri bugreportUri, Uri screenshotUri) {
11601cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final Account sendToAccount = findSendToAccount();
11701cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final Intent intent = new Intent(Intent.ACTION_SEND);
11846899d1b5d606e9349a40079b60034e3cf6eaafbGuang Zhu        intent.addCategory(Intent.CATEGORY_DEFAULT);
119d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        intent.setType("application/octet-stream");
1209ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
12101cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final StringBuilder sb = new StringBuilder();
122d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        sb.append(SystemProperties.get("ro.build.description"));
123d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        sb.append("\n(Sent from BugMailer)");
1249ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        intent.putExtra(Intent.EXTRA_TEXT, (CharSequence)sb);
12501cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        if (screenshotUri != null) {
12601cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            final ArrayList<Uri> attachments = new ArrayList<Uri>();
12701cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            attachments.add(bugreportUri);
12801cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            attachments.add(screenshotUri);
12901cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            intent.setAction(Intent.ACTION_SEND_MULTIPLE);
13001cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
13101cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        } else {
13201cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            intent.putExtra(Intent.EXTRA_STREAM, bugreportUri);
13301cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        }
134d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        if (sendToAccount != null) {
1359ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu            intent.putExtra(Intent.EXTRA_EMAIL, new String[]{sendToAccount.name});
1369ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu            return intent;
137d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu        }
1389ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        return null;
139d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu    }
140d4cd3249e37e5689fc4a8c2858351ec9bebb467cGuang Zhu
1418c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    private Account findSendToAccount() {
14201cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert        final IAccountManager accountManager = IAccountManager.Stub.asInterface(ServiceManager
1438c658e058446ad69fb056b2160340d708582b9eeGuang Zhu                .getService(Context.ACCOUNT_SERVICE));
144818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        if (accountManager == null) {
145818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            Log.e(LOG_TAG, "Cannot get AccountManager, is the system running?");
146818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu            return null;
147818b58c3cc3d9f99d65bc9e4e7ff5b80021079ecGuang Zhu        }
1488c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        Account[] accounts = null;
1498c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        Account foundAccount = null;
1509ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
1519ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        if (!preferredDomain.startsWith("@")) {
1529ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu            preferredDomain = "@" + preferredDomain;
1539ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu        }
1548c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        try {
1558c658e058446ad69fb056b2160340d708582b9eeGuang Zhu            accounts = accountManager.getAccounts(null);
1568c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        } catch (RemoteException e) {
15701cef7d875c77ad5efed9e73d0e3d60a258f79deAlon Albert            // ignore
1588c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        }
1598c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        if (accounts != null) {
1608c658e058446ad69fb056b2160340d708582b9eeGuang Zhu            for (Account account : accounts) {
1619ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                if (EMAIL_REGEX.matcher(account.name).matches()) {
1629ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                    if (!preferredDomain.isEmpty()) {
1639ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        // if we have a preferred domain and it matches, return; otherwise keep
1649ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        // looking
1659ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        if (account.name.endsWith(preferredDomain)) {
1669ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                            return account;
1679ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        } else {
1689ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                            foundAccount = account;
1699ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        }
1709ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        // if we don't have a preferred domain, just return since it looks like
1719ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        // an email address
1729ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                    } else {
1739ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                        return account;
1749ebc639a313d143ade1293cb5932b446d5e623d5Guang Zhu                    }
1758c658e058446ad69fb056b2160340d708582b9eeGuang Zhu                }
1768c658e058446ad69fb056b2160340d708582b9eeGuang Zhu            }
1778c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        }
1788c658e058446ad69fb056b2160340d708582b9eeGuang Zhu        return foundAccount;
1798c658e058446ad69fb056b2160340d708582b9eeGuang Zhu    }
1808c658e058446ad69fb056b2160340d708582b9eeGuang Zhu}
181