Add FerrochromeApp as a share target
Allow sharing text data to FerrochromeApp, if text looks like an URL
(supports http / https / mailto link for now), open the link in VM.
Add a new OpenUrlActivity in FerrochromeApp to handle this feature.
OpenUrlActivity is launched with the 'singleTask' launch mode and this
ensures it is instantiated in the same taskAffinity task as the
FerrochromeActivity. It then bounces the share Intent to the already
launched VM activity.
Change launch mode of VmLauncherApp to 'singleTop' so that we can send
Intent to the already launched VM activity. If we don't use 'singleTop'
launch mode then we would instead create multiple instance of the VM
activity. When the VM activity receives a intent via onNewIntent(), it
sends the Intent payload to the VM data sharing service.
KI: VM need to be logged in first for link sharing to work.
Bug: 348303697
Test: 1. Launch FerrochromeApp and login
2. Switch to another app to select a link
3. Share the link to FerrochromeApp
Change-Id: I39742d4e897caaa37595f50697540196d0393946
diff --git a/vmlauncher_app/AndroidManifest.xml b/vmlauncher_app/AndroidManifest.xml
index e7a23dc..c6ab1f2 100644
--- a/vmlauncher_app/AndroidManifest.xml
+++ b/vmlauncher_app/AndroidManifest.xml
@@ -17,8 +17,9 @@
android:exported="true">
<intent-filter>
<action android:name="android.virtualization.VM_LAUNCHER" />
+ <action android:name="android.virtualization.VM_OPEN_URL" />
<category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
+ </intent-filter>
</activity>
</application>
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index 105ae03..0b93968 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -23,6 +23,7 @@
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.Intent;
import android.crosvm.ICrosvmAndroidDisplayService;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -80,12 +81,17 @@
public class MainActivity extends Activity implements InputManager.InputDeviceListener {
private static final String TAG = "VmLauncherApp";
private static final String VM_NAME = "my_custom_vm";
+
private static final boolean DEBUG = true;
+ private static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 101;
+
+ private static final String ACTION_VM_LAUNCHER = "android.virtualization.VM_LAUNCHER";
+ private static final String ACTION_VM_OPEN_URL = "android.virtualization.VM_OPEN_URL";
+
private ExecutorService mExecutorService;
private VirtualMachine mVirtualMachine;
private CursorHandler mCursorHandler;
private ClipboardManager mClipboardManager;
- private static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 101;
private VirtualMachineConfig createVirtualMachineConfig(String jsonPath) {
VirtualMachineConfig.Builder configBuilder =
@@ -321,6 +327,12 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ String action = getIntent().getAction();
+ if (!ACTION_VM_LAUNCHER.equals(action)) {
+ finish();
+ Log.e(TAG, "onCreate unsupported intent action: " + action);
+ return;
+ }
checkAndRequestRecordAudioPermission();
mExecutorService = Executors.newCachedThreadPool();
try {
@@ -571,6 +583,7 @@
private static final byte READ_CLIPBOARD_FROM_VM = 0;
private static final byte WRITE_CLIPBOARD_TYPE_EMPTY = 1;
private static final byte WRITE_CLIPBOARD_TYPE_TEXT_PLAIN = 2;
+ private static final byte OPEN_URL = 3;
private ClipboardManager getClipboardManager() {
if (mClipboardManager == null) {
@@ -688,6 +701,32 @@
}
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ String action = intent.getAction();
+ if (!ACTION_VM_OPEN_URL.equals(action)) {
+ Log.e(TAG, "onNewIntent unsupported intent action: " + action);
+ return;
+ }
+ Log.d(TAG, "onNewIntent intent action: " + action);
+ String text = intent.getStringExtra(Intent.EXTRA_TEXT);
+ if (text != null) {
+ mExecutorService.execute(
+ () -> {
+ byte[] data = text.getBytes();
+ try (ParcelFileDescriptor pfd = connectDataSharingService();
+ OutputStream stream =
+ new FileOutputStream(pfd.getFileDescriptor())) {
+ stream.write(constructClipboardHeader(OPEN_URL, data.length));
+ stream.write(data);
+ Log.d(TAG, "Successfully sent URL to the VM");
+ } catch (IOException | VirtualMachineException e) {
+ Log.e(TAG, "Failed to send URL to the VM", e);
+ }
+ });
+ }
+ }
+
@FunctionalInterface
public interface RemoteExceptionCheckedFunction<T> {
void apply(T t) throws RemoteException;