FileSender.java revision ba512c3d840bf151b9ea04df924d2e7f3c227501
1/*
2 * Copyright (C) 2015 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
17package com.android.traceur;
18
19import android.accounts.Account;
20import android.accounts.AccountManager;
21import android.app.Notification;
22import android.app.NotificationManager;
23import android.app.PendingIntent;
24import android.content.Context;
25import android.support.v4.content.FileProvider;
26import android.content.Intent;
27import android.net.Uri;
28import android.os.SystemProperties;
29import android.util.Patterns;
30
31import java.io.File;
32
33/**
34 * Sends bugreport-y files, adapted from fw/base/packages/Shell's BugreportReceiver.
35 */
36public class FileSender {
37
38    private static final String AUTHORITY = "com.android.traceur.files";
39
40    public static void postNotification(Context context, File file) {
41        // Files are kept on private storage, so turn into Uris that we can
42        // grant temporary permissions for.
43        final Uri traceUri = getUriForFile(context, file);
44
45        Intent sendIntent = buildSendIntent(context, traceUri);
46        sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
47
48        final Notification.Builder builder =
49            new Notification.Builder(context, Receiver.NOTIFICATION_CHANNEL)
50                .setSmallIcon(R.drawable.stat_sys_adb)
51                .setContentTitle(context.getString(R.string.trace_saved))
52                .setTicker(context.getString(R.string.trace_saved))
53                .setContentText(context.getString(R.string.tap_to_share))
54                .setContentIntent(PendingIntent.getActivity(
55                        context, traceUri.hashCode(), sendIntent, PendingIntent.FLAG_ONE_SHOT
56                                | PendingIntent.FLAG_CANCEL_CURRENT))
57                .setAutoCancel(true)
58                .setLocalOnly(true)
59                .setColor(context.getColor(
60                        com.android.internal.R.color.system_notification_accent_color));
61
62        NotificationManager.from(context).notify(file.getName(), 0, builder.build());
63    }
64
65    public static void send(Context context, File file) {
66        // Files are kept on private storage, so turn into Uris that we can
67        // grant temporary permissions for.
68        final Uri traceUri = getUriForFile(context, file);
69
70        Intent sendIntent = buildSendIntent(context, traceUri);
71        sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
72
73        context.startActivity(sendIntent);
74    }
75
76    private static Uri getUriForFile(Context context, File file) {
77        return FileProvider.getUriForFile(context, AUTHORITY, file);
78    }
79
80    /**
81     * Build {@link Intent} that can be used to share the given bugreport.
82     */
83    private static Intent buildSendIntent(Context context, Uri traceUri) {
84        final Intent intent = new Intent(Intent.ACTION_SEND);
85        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
86        intent.addCategory(Intent.CATEGORY_DEFAULT);
87        intent.setType("application/vnd.android.systrace");
88
89        intent.putExtra(Intent.EXTRA_SUBJECT, traceUri.getLastPathSegment());
90        intent.putExtra(Intent.EXTRA_TEXT, SystemProperties.get("ro.build.description"));
91        intent.putExtra(Intent.EXTRA_STREAM, traceUri);
92
93        final Account sendToAccount = findSendToAccount(context);
94        if (sendToAccount != null) {
95            intent.putExtra(Intent.EXTRA_EMAIL, new String[] { sendToAccount.name });
96        }
97
98        return intent;
99    }
100
101    /**
102     * Find the best matching {@link Account} based on build properties.
103     */
104    private static Account findSendToAccount(Context context) {
105        final AccountManager am = (AccountManager) context.getSystemService(
106                Context.ACCOUNT_SERVICE);
107
108        String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
109        if (!preferredDomain.startsWith("@")) {
110            preferredDomain = "@" + preferredDomain;
111        }
112
113        final Account[] accounts = am.getAccounts();
114        Account foundAccount = null;
115        for (Account account : accounts) {
116            if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
117                if (!preferredDomain.isEmpty()) {
118                    // if we have a preferred domain and it matches, return; otherwise keep
119                    // looking
120                    if (account.name.endsWith(preferredDomain)) {
121                        return account;
122                    } else {
123                        foundAccount = account;
124                    }
125                    // if we don't have a preferred domain, just return since it looks like
126                    // an email address
127                } else {
128                    return account;
129                }
130            }
131        }
132        return foundAccount;
133    }
134}
135