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