blob: b6b76a9703916ea383a186103c5668a2aafa8cd9 [file] [log] [blame]
/*
* Copyright (C) 2022 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.apiimplementation;
import android.app.Activity;
import android.app.sdksandbox.interfaces.IActivityStarter;
import android.app.sdksandbox.interfaces.ISdkApi;
import android.app.sdksandbox.sdkprovider.SdkSandboxController;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.VideoView;
import com.android.modules.utils.build.SdkLevel;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SdkApi extends ISdkApi.Stub {
private static final String WEB_VIEW_LINK = "https://youtu.be/pQdzFbmlvOo";
private static final String VIDEO_URL_KEY = "video-url";
private final Context mContext;
private WebView mWebView;
public SdkApi(Context sdkContext) {
mContext = sdkContext;
preloadWebViewForActivity(sdkContext);
}
@Override
public String createFile(int sizeInMb) throws RemoteException {
Path path;
if (SdkLevel.isAtLeastU()) {
// U device should be have customized sdk context that allows all storage APIs on
// context to utlize per-sdk storage
path = Paths.get(mContext.getFilesDir().getPath(), "file.txt");
// Verify per-sdk storage is being used
if (!path.startsWith(mContext.getDataDir().getPath())) {
throw new IllegalStateException("Customized Sdk Context is not being used");
}
} else {
path = Paths.get(mContext.getDataDir().getPath(), "file.txt");
}
try {
Files.deleteIfExists(path);
Files.createFile(path);
final byte[] buffer = new byte[sizeInMb * 1024 * 1024];
Files.write(path, buffer);
final File file = new File(path.toString());
final long actualFilzeSize = file.length() / (1024 * 1024);
return "Created " + actualFilzeSize + " MB file successfully";
} catch (IOException e) {
throw new RemoteException(e);
}
}
@Override
public String getMessage() {
return "Message from sdk in the sandbox process";
}
@Override
public String getSyncedSharedPreferencesString(String key) {
return getClientSharedPreferences().getString(key, "");
}
@Override
public String getSandboxDump() {
// Check if the SDK can access device volume.
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
int curVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
return "Current music volume: " + curVolume + ", max music volume: " + maxVolume;
}
@Override
public void startActivity(IActivityStarter iActivityStarter, Bundle params)
throws RemoteException {
if (!SdkLevel.isAtLeastU()) {
throw new IllegalStateException("Starting activity requires Android U or above!");
}
final String videoUrl = params.getString(VIDEO_URL_KEY, null);
SdkSandboxController controller = mContext.getSystemService(SdkSandboxController.class);
IBinder token =
controller.registerSdkSandboxActivityHandler(
activity -> {
View mediaView;
if (videoUrl != null) {
mediaView = createVideoAd(activity, videoUrl);
} else {
mediaView = mWebView;
}
new ActivityHandler(activity, mContext, mediaView).buildLayout();
});
iActivityStarter.startActivity(token);
}
private SharedPreferences getClientSharedPreferences() {
return mContext.getSystemService(SdkSandboxController.class).getClientSharedPreferences();
}
private VideoView createVideoAd(Activity activity, String videoUrl) {
final VideoView videoView = new VideoView(activity);
videoView.setVideoURI(Uri.parse(videoUrl));
videoView.requestFocus();
videoView.setOnPreparedListener(mp -> videoView.start());
videoView.setOnCompletionListener(
new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
videoView.setOnTouchListener(
(view, event) -> {
Intent visitUrl = new Intent(Intent.ACTION_VIEW);
visitUrl.setData(Uri.parse("https://www.google.com"));
visitUrl.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(visitUrl);
return true;
});
}
});
return videoView;
}
private void preloadWebViewForActivity(Context sdkContext) {
mWebView = new WebView(sdkContext);
initializeSettings(mWebView.getSettings());
// Handle Urls locally
mWebView.setWebViewClient(
new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(
WebView view, WebResourceRequest request) {
return false;
}
});
mWebView.loadUrl(WEB_VIEW_LINK);
}
private void initializeSettings(WebSettings settings) {
settings.setJavaScriptEnabled(true);
settings.setGeolocationEnabled(true);
settings.setSupportZoom(true);
settings.setDatabaseEnabled(true);
settings.setDomStorageEnabled(true);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
// Default layout behavior for chrome on android.
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
}
}