• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.ondevicepersonalization.services.download.mdd;
18 
19 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
20 import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
21 
22 import android.content.Context;
23 import android.net.Uri;
24 import android.util.Log;
25 
26 import com.google.android.libraries.mobiledatadownload.DownloadException;
27 import com.google.android.libraries.mobiledatadownload.downloader.DownloadRequest;
28 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
29 import com.google.android.libraries.mobiledatadownload.file.Opener;
30 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
31 import com.google.android.libraries.mobiledatadownload.file.openers.WriteStreamOpener;
32 import com.google.common.io.ByteStreams;
33 import com.google.common.util.concurrent.Futures;
34 import com.google.common.util.concurrent.ListenableFuture;
35 
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.util.Set;
39 import java.util.concurrent.Executor;
40 
41 /**
42  * A {@link FileDownloader} that "downloads" by copying the file from the Resources.
43  * Files for local download should be placed in the package's Resources.
44  *
45  * <p>Note that OnDevicePersonalizationLocalFileDownloader ignores DownloadConditions.
46  */
47 public final class OnDevicePersonalizationLocalFileDownloader implements FileDownloader {
48 
49     private static final String TAG = "OnDevicePersonalizationLocalFileDownloader";
50 
51     /**
52      * The uri to download should be formatted as an android.resource uri:
53      * android.resource://<package_name>/<resource_type>/<resource_name>
54      */
55     private static final Set<String> sDebugSchemes = Set.of("android.resource", "file");
56 
57     private final Executor mExecutor;
58     private final SynchronousFileStorage mFileStorage;
59     private final Context mContext;
60 
OnDevicePersonalizationLocalFileDownloader( SynchronousFileStorage fileStorage, Executor executor, Context context)61     public OnDevicePersonalizationLocalFileDownloader(
62             SynchronousFileStorage fileStorage, Executor executor,
63             Context context) {
64         this.mFileStorage = fileStorage;
65         this.mExecutor = executor;
66         this.mContext = context;
67     }
68 
69     /**
70      * Determines if given uri is local odp uri
71      *
72      * @return true if uri is a local odp uri, false otherwise
73      */
isLocalOdpUri(Uri uri)74     public static boolean isLocalOdpUri(Uri uri) {
75         String scheme = uri.getScheme();
76         if (scheme != null && sDebugSchemes.contains(scheme)) {
77             return true;
78         }
79         return false;
80     }
81 
82     /**
83      * Performs a localFile download for the given request
84      */
85     @Override
startDownloading(DownloadRequest downloadRequest)86     public ListenableFuture<Void> startDownloading(DownloadRequest downloadRequest) {
87         return Futures.submitAsync(() -> startDownloadingInternal(downloadRequest),
88                 mExecutor);
89     }
90 
startDownloadingInternal(DownloadRequest downloadRequest)91     private ListenableFuture<Void> startDownloadingInternal(DownloadRequest downloadRequest) {
92         Uri fileUri = downloadRequest.fileUri();
93         String urlToDownload = downloadRequest.urlToDownload();
94         Uri uriToDownload = Uri.parse(urlToDownload);
95         // Strip away the query params for local download.
96         uriToDownload = new Uri.Builder()
97                 .scheme(uriToDownload.getScheme())
98                 .authority(uriToDownload.getAuthority())
99                 .path(uriToDownload.getPath()).build();
100         Log.d(TAG, "Starting local download for url: " + urlToDownload);
101 
102         try {
103             Opener<OutputStream> writeStreamOpener = WriteStreamOpener.create();
104             long writtenBytes;
105             try (OutputStream out = mFileStorage.open(fileUri, writeStreamOpener)) {
106                 InputStream in = mContext.getContentResolver().openInputStream(uriToDownload);
107                 writtenBytes = ByteStreams.copy(in, out);
108             }
109             Log.d(TAG,
110                     "File URI " + fileUri + " download complete, writtenBytes: %d" + writtenBytes);
111         } catch (Exception e) {
112             Log.e(TAG, "%s: startDownloading got exception", e);
113             return immediateFailedFuture(
114                     DownloadException.builder()
115                             .setDownloadResultCode(
116                                     DownloadException.DownloadResultCode
117                                             .ANDROID_DOWNLOADER_HTTP_ERROR)
118                             .build());
119         }
120 
121         return immediateVoidFuture();
122     }
123 }
124