blob: 9de5e8db339df57c455d42c6d909f579e60a5e20 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.mojo.shell;
import android.app.Activity;
import android.content.Intent;
import android.os.Parcel;
import org.chromium.base.ApplicationStatus;
import org.chromium.mojo.application.ServiceFactoryBinder;
import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.bindings.InterfaceRequest;
import org.chromium.mojo.intent.IntentReceiver;
import org.chromium.mojo.intent.IntentReceiverManager;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.RunLoop;
import org.chromium.mojo.system.impl.CoreImpl;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Java implementation for services/android/intent_receiver.mojom. This class creates intents for
* privileged mojo applications and routes received intents back to the mojo application.
*/
public class IntentReceiverRegistry
implements IntentReceiverManager, ServiceFactoryBinder<IntentReceiverManager> {
private static class LazyHolder {
private static final IntentReceiverRegistry INSTANCE = new IntentReceiverRegistry();
}
/**
* Returns the instance.
*/
public static IntentReceiverRegistry getInstance() {
return LazyHolder.INSTANCE;
}
/**
* The runloop the service runs on.
*/
private RunLoop mRunLoop = null;
private final Map<String, IntentReceiver> mReceiversByUuid = new HashMap<>();
private final Map<IntentReceiver, String> mUuidsByReceiver = new HashMap<>();
private int mLastRequestCode = 0;
private IntentReceiverRegistry() {}
public void onIntentReceived(final Intent intent) {
String uuid = intent.getAction();
if (uuid == null) return;
final IntentReceiver receiver = mReceiversByUuid.get(uuid);
if (receiver == null) return;
mRunLoop.postDelayedTask(new Runnable() {
@Override
public void run() {
receiver.onIntent(intentToBytes(intent));
}
}, 0);
}
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
String uuid = Integer.toString(requestCode);
if (uuid == null) return;
final IntentReceiver receiver = mReceiversByUuid.get(uuid);
if (receiver == null) return;
mRunLoop.postDelayedTask(new Runnable() {
@Override
public void run() {
if (resultCode == Activity.RESULT_OK) {
receiver.onIntent(intentToBytes(data));
} else {
receiver.onIntent(null);
}
receiver.close();
}
}, 0);
unregisterReceiver(receiver);
}
private static byte[] intentToBytes(Intent intent) {
Parcel p = Parcel.obtain();
intent.writeToParcel(p, 0);
p.setDataPosition(0);
return p.marshall();
}
/**
* @see IntentReceiverManager#registerIntentReceiver(IntentReceiver,
* RegisterIntentReceiverResponse)
*/
@Override
public void registerIntentReceiver(
IntentReceiver receiver, RegisterIntentReceiverResponse callback) {
registerErrorHandler(receiver);
String uuid = UUID.randomUUID().toString();
Intent intent = new Intent(
uuid, null, ApplicationStatus.getApplicationContext(), IntentReceiverService.class);
mReceiversByUuid.put(uuid, receiver);
mUuidsByReceiver.put(receiver, uuid);
callback.call(intentToBytes(intent));
}
/**
* @see IntentReceiverManager#registerActivityResultReceiver(IntentReceiver,
* RegisterActivityResultReceiverResponse)
*/
@Override
public void registerActivityResultReceiver(
IntentReceiver receiver, RegisterActivityResultReceiverResponse callback) {
registerErrorHandler(receiver);
String uuid;
// Handle unlikely overflows.
do {
++mLastRequestCode;
if (mLastRequestCode < 1) {
mLastRequestCode = 1;
}
uuid = Integer.toString(mLastRequestCode);
} while (mReceiversByUuid.keySet().contains(uuid));
mReceiversByUuid.put(uuid, receiver);
mUuidsByReceiver.put(receiver, uuid);
Intent intent = new Intent(
uuid, null, ApplicationStatus.getApplicationContext(), IntentReceiverService.class);
intent.addCategory(IntentReceiverService.CATEGORY_START_ACTIVITY_FOR_RESULT);
callback.call(intentToBytes(intent));
}
/**
* @see IntentReceiverManager#close()
*/
@Override
public void close() {}
/**
* @see IntentReceiverManager#onConnectionError(MojoException)
*/
@Override
public void onConnectionError(MojoException e) {}
/**
* @see ServiceFactoryBinder#bind(InterfaceRequest)
*/
@Override
public void bind(InterfaceRequest<IntentReceiverManager> request) {
if (mRunLoop == null) {
mRunLoop = CoreImpl.getInstance().getCurrentRunLoop();
}
assert mRunLoop == CoreImpl.getInstance().getCurrentRunLoop();
IntentReceiverManager.MANAGER.bind(this, request);
}
/**
* @see ServiceFactoryBinder#getInterfaceName()
*/
@Override
public String getInterfaceName() {
return IntentReceiverManager.MANAGER.getName();
}
private void unregisterReceiver(IntentReceiver receiver) {
IntentReceiverRegistry registry = getInstance();
String uuid = registry.mUuidsByReceiver.get(receiver);
if (uuid != null) {
registry.mUuidsByReceiver.remove(receiver);
registry.mReceiversByUuid.remove(uuid);
}
}
private void registerErrorHandler(final IntentReceiver receiver) {
if (receiver instanceof IntentReceiver.Proxy) {
IntentReceiver.Proxy proxy = (IntentReceiver.Proxy) receiver;
proxy.getProxyHandler().setErrorHandler(new ConnectionErrorHandler() {
@Override
public void onConnectionError(MojoException e) {
unregisterReceiver(receiver);
}
});
}
}
}