blob: 23f2cc5eb9b43018035bd2902bdd77398811f534 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.phone.testapps.embmsdownload;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.telephony.MbmsDownloadSession;
import android.telephony.SubscriptionManager;
import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.FileServiceInfo;
import android.telephony.mbms.MbmsDownloadSessionCallback;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.NumberPicker;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EmbmsTestDownloadApp extends Activity {
private static final String LOG_TAG = "EmbmsDownloadApp";
public static final String DOWNLOAD_DONE_ACTION =
"com.android.phone.testapps.embmsdownload.DOWNLOAD_DONE";
private static final String CUSTOM_EMBMS_TEMP_FILE_LOCATION = "customEmbmsTempFiles";
private static final String FILE_AUTHORITY = "com.android.phone.testapps";
private static final String FILE_DOWNLOAD_SCHEME = "filedownload";
private static EmbmsTestDownloadApp sInstance;
private static final class ImageAdapter
extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
static class ImageViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public ImageViewHolder(ImageView view) {
super(view);
imageView = view;
}
}
private final List<Uri> mImageUris = new ArrayList<>();
@Override
public ImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ImageView view = new ImageView(parent.getContext());
view.setAdjustViewBounds(true);
view.setMaxHeight(500);
return new ImageViewHolder(view);
}
@Override
public void onBindViewHolder(ImageViewHolder holder, int position) {
holder.imageView.setImageURI(mImageUris.get(position));
}
@Override
public int getItemCount() {
return mImageUris.size();
}
public void addImage(Uri uri) {
mImageUris.add(uri);
notifyDataSetChanged();
}
}
private final class FileServiceInfoAdapter
extends ArrayAdapter<FileServiceInfo> {
public FileServiceInfoAdapter(Context context) {
super(context, android.R.layout.simple_spinner_item);
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
FileServiceInfo info = getItem(position);
TextView result = new TextView(EmbmsTestDownloadApp.this);
result.setText(info.getNameForLocale(info.getLocales().get(0)));
return result;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
FileServiceInfo info = getItem(position);
TextView result = new TextView(EmbmsTestDownloadApp.this);
String text = "name="
+ info.getNameForLocale(info.getLocales().get(0))
+ ", "
+ "numFiles="
+ info.getFiles().size();
result.setText(text);
return result;
}
public void update(List<FileServiceInfo> services) {
clear();
addAll(services);
}
}
private final class DownloadRequestAdapter
extends ArrayAdapter<DownloadRequest> {
public DownloadRequestAdapter(Context context) {
super(context, android.R.layout.simple_spinner_item);
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
DownloadRequest request = getItem(position);
TextView result = new TextView(EmbmsTestDownloadApp.this);
result.setText(request.getSourceUri().toSafeString());
return result;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
}
private MbmsDownloadSessionCallback mCallback = new MbmsDownloadSessionCallback() {
@Override
public void onError(int errorCode, String message) {
runOnUiThread(() -> Toast.makeText(EmbmsTestDownloadApp.this,
"Error " + errorCode + ": " + message, Toast.LENGTH_SHORT).show());
}
@Override
public void onFileServicesUpdated(List<FileServiceInfo> services) {
EmbmsTestDownloadApp.this.runOnUiThread(() ->
Toast.makeText(EmbmsTestDownloadApp.this,
"Got services length " + services.size(),
Toast.LENGTH_SHORT).show());
updateFileServicesList(services);
}
@Override
public void onMiddlewareReady() {
runOnUiThread(() -> Toast.makeText(EmbmsTestDownloadApp.this,
"Initialization done", Toast.LENGTH_SHORT).show());
}
};
private MbmsDownloadSession mDownloadManager;
private Handler mHandler;
private HandlerThread mHandlerThread;
private FileServiceInfoAdapter mFileServiceInfoAdapter;
private DownloadRequestAdapter mDownloadRequestAdapter;
private ImageAdapter mImageAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sInstance = this;
mHandlerThread = new HandlerThread("EmbmsDownloadWorker");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mFileServiceInfoAdapter = new FileServiceInfoAdapter(this);
mDownloadRequestAdapter = new DownloadRequestAdapter(this);
RecyclerView downloadedImages = (RecyclerView) findViewById(R.id.downloaded_images);
downloadedImages.setLayoutManager(
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
mImageAdapter = new ImageAdapter();
downloadedImages.setAdapter(mImageAdapter);
Button bindButton = (Button) findViewById(R.id.bind_button);
bindButton.setOnClickListener((view) -> {
mDownloadManager = MbmsDownloadSession.create(this, mCallback, mHandler);
});
Button setTempFileRootButton = (Button) findViewById(R.id.set_temp_root_button);
setTempFileRootButton.setOnClickListener((view) -> {
File downloadDir = new File(EmbmsTestDownloadApp.this.getFilesDir(),
CUSTOM_EMBMS_TEMP_FILE_LOCATION);
downloadDir.mkdirs();
mDownloadManager.setTempFileRootDirectory(downloadDir);
Toast.makeText(EmbmsTestDownloadApp.this,
"temp file root set to " + downloadDir, Toast.LENGTH_SHORT).show();
});
Button getFileServicesButton = (Button) findViewById(R.id.get_file_services_button);
getFileServicesButton.setOnClickListener((view) -> mHandler.post(() -> {
mDownloadManager.requestUpdateFileServices(Collections.singletonList("Class1"));
}));
final Spinner serviceSelector = (Spinner) findViewById(R.id.available_file_services);
serviceSelector.setAdapter(mFileServiceInfoAdapter);
Button requestDlButton = (Button) findViewById(R.id.request_dl_button);
requestDlButton.setOnClickListener((view) -> {
if (mDownloadManager == null) {
Toast.makeText(EmbmsTestDownloadApp.this,
"No download service bound", Toast.LENGTH_SHORT).show();
return;
}
FileServiceInfo serviceInfo =
(FileServiceInfo) serviceSelector.getSelectedItem();
if (serviceInfo == null) {
Toast.makeText(EmbmsTestDownloadApp.this,
"No file service selected", Toast.LENGTH_SHORT).show();
return;
}
performDownload(serviceInfo);
});
Button requestCleanupButton = (Button) findViewById(R.id.request_cleanup_button);
requestCleanupButton.setOnClickListener((view) ->
SideChannel.triggerCleanup(EmbmsTestDownloadApp.this));
Button requestSpuriousTempFilesButton =
(Button) findViewById(R.id.request_spurious_temp_files_button);
requestSpuriousTempFilesButton.setOnClickListener((view) ->
SideChannel.requestSpuriousTempFiles(EmbmsTestDownloadApp.this,
(FileServiceInfo) serviceSelector.getSelectedItem()));
NumberPicker downloadDelayPicker = (NumberPicker) findViewById(R.id.delay_factor);
downloadDelayPicker.setMinValue(1);
downloadDelayPicker.setMaxValue(50);
Button delayDownloadButton = (Button) findViewById(R.id.delay_download_button);
delayDownloadButton.setOnClickListener((view) ->
SideChannel.delayDownloads(EmbmsTestDownloadApp.this,
downloadDelayPicker.getValue()));
final Spinner downloadRequestSpinner = (Spinner) findViewById(R.id.active_downloads);
downloadRequestSpinner.setAdapter(mDownloadRequestAdapter);
Button cancelDownloadButton = (Button) findViewById(R.id.cancel_download_button);
cancelDownloadButton.setOnClickListener((view) -> {
if (mDownloadManager == null) {
Toast.makeText(EmbmsTestDownloadApp.this,
"No download service bound", Toast.LENGTH_SHORT).show();
return;
}
DownloadRequest request =
(DownloadRequest) downloadRequestSpinner.getSelectedItem();
mDownloadManager.cancelDownload(request);
mDownloadRequestAdapter.remove(request);
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
sInstance = null;
}
public static EmbmsTestDownloadApp getInstance() {
return sInstance;
}
public void onDownloadFailed(int result) {
runOnUiThread(() ->
Toast.makeText(this, "Download failed: " + result, Toast.LENGTH_SHORT).show());
}
// TODO: assumes that process does not get killed. Replace with more robust alternative
public void onDownloadDone(Uri fileLocation) {
Log.i(LOG_TAG, "File completed: " + fileLocation);
File imageFile = new File(fileLocation.getPath());
if (!imageFile.exists()) {
Toast.makeText(this, "Download done but destination doesn't exist", Toast.LENGTH_SHORT)
.show();
return;
}
mImageAdapter.addImage(fileLocation);
}
private void updateFileServicesList(List<FileServiceInfo> services) {
runOnUiThread(() -> mFileServiceInfoAdapter.update(services));
}
private void performDownload(FileServiceInfo info) {
Uri.Builder sourceUriBuilder = new Uri.Builder()
.scheme(FILE_DOWNLOAD_SCHEME)
.authority(FILE_AUTHORITY);
if (info.getServiceId().contains("2")) {
sourceUriBuilder.path("/*");
} else {
sourceUriBuilder.path("/image.png");
}
Intent completionIntent = new Intent(DOWNLOAD_DONE_ACTION);
completionIntent.setClass(this, DownloadCompletionReceiver.class);
DownloadRequest request = new DownloadRequest.Builder()
.setServiceInfo(info)
.setSource(sourceUriBuilder.build())
.setAppIntent(completionIntent)
.setSubscriptionId(SubscriptionManager.getDefaultSubscriptionId())
.build();
mDownloadManager.download(request);
mDownloadRequestAdapter.add(request);
}
}