Add way to use sysui as a broadcast relay for slices
Test: runtest systemui Bug: 78139069 Change-Id: I64c4d56cca005cec7204bf45215bb7b0015f4571
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.settingslib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Utility class that allows Settings to use SystemUI to relay broadcasts related to pinned slices.
|
||||
*/
|
||||
public class SliceBroadcastRelay {
|
||||
|
||||
public static final String ACTION_REGISTER
|
||||
= "com.android.settingslib.action.REGISTER_SLICE_RECEIVER";
|
||||
public static final String ACTION_UNREGISTER
|
||||
= "com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER";
|
||||
public static final String SYSTEMUI_PACKAGE = "com.android.systemui";
|
||||
|
||||
public static final String EXTRA_URI = "uri";
|
||||
public static final String EXTRA_RECEIVER = "receiver";
|
||||
public static final String EXTRA_FILTER = "filter";
|
||||
|
||||
public static void registerReceiver(Context context, Uri registerKey,
|
||||
Class<? extends BroadcastReceiver> receiver, IntentFilter filter) {
|
||||
Intent registerBroadcast = new Intent(ACTION_REGISTER);
|
||||
registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
|
||||
registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
|
||||
Process.myUserHandle().getIdentifier()));
|
||||
registerBroadcast.putExtra(EXTRA_RECEIVER,
|
||||
new ComponentName(context.getPackageName(), receiver.getName()));
|
||||
registerBroadcast.putExtra(EXTRA_FILTER, filter);
|
||||
|
||||
context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
|
||||
}
|
||||
|
||||
public static void unregisterReceivers(Context context, Uri registerKey) {
|
||||
Intent registerBroadcast = new Intent(ACTION_UNREGISTER);
|
||||
registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
|
||||
registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
|
||||
Process.myUserHandle().getIdentifier()));
|
||||
|
||||
context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
|
||||
}
|
||||
}
|
||||
@@ -350,6 +350,7 @@
|
||||
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
|
||||
<item>com.android.systemui.ScreenDecorations</item>
|
||||
<item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
|
||||
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
|
||||
</string-array>
|
||||
|
||||
<!-- SystemUI vender service, used in config_systemUIServiceComponents. -->
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.systemui;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settingslib.SliceBroadcastRelay;
|
||||
|
||||
/**
|
||||
* Allows settings to register certain broadcasts to launch the settings app for pinned slices.
|
||||
* @see SliceBroadcastRelay
|
||||
*/
|
||||
public class SliceBroadcastRelayHandler extends SystemUI {
|
||||
private static final String TAG = "SliceBroadcastRelay";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final ArrayMap<Uri, BroadcastRelay> mRelays = new ArrayMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DEBUG) Log.d(TAG, "Start");
|
||||
IntentFilter filter = new IntentFilter(SliceBroadcastRelay.ACTION_REGISTER);
|
||||
filter.addAction(SliceBroadcastRelay.ACTION_UNREGISTER);
|
||||
mContext.registerReceiver(mReceiver, filter);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void handleIntent(Intent intent) {
|
||||
if (SliceBroadcastRelay.ACTION_REGISTER.equals(intent.getAction())) {
|
||||
Uri uri = intent.getParcelableExtra(SliceBroadcastRelay.EXTRA_URI);
|
||||
ComponentName receiverClass =
|
||||
intent.getParcelableExtra(SliceBroadcastRelay.EXTRA_RECEIVER);
|
||||
IntentFilter filter = intent.getParcelableExtra(SliceBroadcastRelay.EXTRA_FILTER);
|
||||
if (DEBUG) Log.d(TAG, "Register " + uri + " " + receiverClass + " " + filter);
|
||||
getOrCreateRelay(uri).register(mContext, receiverClass, filter);
|
||||
} else if (SliceBroadcastRelay.ACTION_UNREGISTER.equals(intent.getAction())) {
|
||||
Uri uri = intent.getParcelableExtra(SliceBroadcastRelay.EXTRA_URI);
|
||||
if (DEBUG) Log.d(TAG, "Unregister " + uri);
|
||||
getAndRemoveRelay(uri).unregister(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
private BroadcastRelay getOrCreateRelay(Uri uri) {
|
||||
BroadcastRelay ret = mRelays.get(uri);
|
||||
if (ret == null) {
|
||||
ret = new BroadcastRelay(uri);
|
||||
mRelays.put(uri, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private BroadcastRelay getAndRemoveRelay(Uri uri) {
|
||||
return mRelays.remove(uri);
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
handleIntent(intent);
|
||||
}
|
||||
};
|
||||
|
||||
private static class BroadcastRelay extends BroadcastReceiver {
|
||||
|
||||
private final ArraySet<ComponentName> mReceivers = new ArraySet<>();
|
||||
private final UserHandle mUserId;
|
||||
|
||||
public BroadcastRelay(Uri uri) {
|
||||
mUserId = new UserHandle(ContentProvider.getUserIdFromUri(uri));
|
||||
}
|
||||
|
||||
public void register(Context context, ComponentName receiver, IntentFilter filter) {
|
||||
mReceivers.add(receiver);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
public void unregister(Context context) {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
for (ComponentName receiver : mReceivers) {
|
||||
intent.setComponent(receiver);
|
||||
if (DEBUG) Log.d(TAG, "Forwarding " + receiver + " " + intent + " " + mUserId);
|
||||
context.sendBroadcastAsUser(intent, mUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,12 @@
|
||||
<service
|
||||
android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
|
||||
android:process=":killable" />
|
||||
|
||||
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.action.TEST_ACTION" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="android.testing.TestableInstrumentation"
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.systemui;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import com.android.settingslib.SliceBroadcastRelay;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
public class SliceBroadcastRelayHandlerTest extends SysuiTestCase {
|
||||
|
||||
private static final String TEST_ACTION = "com.android.systemui.action.TEST_ACTION";
|
||||
|
||||
@Test
|
||||
public void testRegister() {
|
||||
Uri testUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority("something")
|
||||
.path("test")
|
||||
.build();
|
||||
SliceBroadcastRelayHandler relayHandler = new SliceBroadcastRelayHandler();
|
||||
relayHandler.mContext = spy(mContext);
|
||||
|
||||
Intent intent = new Intent(SliceBroadcastRelay.ACTION_REGISTER);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_RECEIVER,
|
||||
new ComponentName(mContext.getPackageName(), Receiver.class.getName()));
|
||||
IntentFilter value = new IntentFilter(TEST_ACTION);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_FILTER, value);
|
||||
|
||||
relayHandler.handleIntent(intent);
|
||||
verify(relayHandler.mContext).registerReceiver(any(), eq(value));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregister() {
|
||||
Uri testUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority("something")
|
||||
.path("test")
|
||||
.build();
|
||||
SliceBroadcastRelayHandler relayHandler = new SliceBroadcastRelayHandler();
|
||||
relayHandler.mContext = spy(mContext);
|
||||
|
||||
Intent intent = new Intent(SliceBroadcastRelay.ACTION_REGISTER);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_RECEIVER,
|
||||
new ComponentName(mContext.getPackageName(), Receiver.class.getName()));
|
||||
IntentFilter value = new IntentFilter(TEST_ACTION);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_FILTER, value);
|
||||
|
||||
relayHandler.handleIntent(intent);
|
||||
ArgumentCaptor<BroadcastReceiver> relay = ArgumentCaptor.forClass(BroadcastReceiver.class);
|
||||
verify(relayHandler.mContext).registerReceiver(relay.capture(), eq(value));
|
||||
|
||||
intent = new Intent(SliceBroadcastRelay.ACTION_UNREGISTER);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
|
||||
relayHandler.handleIntent(intent);
|
||||
verify(relayHandler.mContext).unregisterReceiver(eq(relay.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelay() {
|
||||
Receiver.sReceiver = mock(BroadcastReceiver.class);
|
||||
Uri testUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority("something")
|
||||
.path("test")
|
||||
.build();
|
||||
SliceBroadcastRelayHandler relayHandler = new SliceBroadcastRelayHandler();
|
||||
relayHandler.mContext = spy(mContext);
|
||||
|
||||
Intent intent = new Intent(SliceBroadcastRelay.ACTION_REGISTER);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_RECEIVER,
|
||||
new ComponentName(mContext.getPackageName(), Receiver.class.getName()));
|
||||
IntentFilter value = new IntentFilter(TEST_ACTION);
|
||||
intent.putExtra(SliceBroadcastRelay.EXTRA_FILTER, value);
|
||||
|
||||
relayHandler.handleIntent(intent);
|
||||
ArgumentCaptor<BroadcastReceiver> relay = ArgumentCaptor.forClass(BroadcastReceiver.class);
|
||||
verify(relayHandler.mContext).registerReceiver(relay.capture(), eq(value));
|
||||
relay.getValue().onReceive(relayHandler.mContext, new Intent(TEST_ACTION));
|
||||
|
||||
verify(Receiver.sReceiver, timeout(2000)).onReceive(any(), any());
|
||||
}
|
||||
|
||||
public static class Receiver extends BroadcastReceiver {
|
||||
private static BroadcastReceiver sReceiver;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (sReceiver != null) sReceiver.onReceive(context, intent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user