Merge "Refactor EphemeralResolverService"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a485f71fd7
@@ -84,6 +84,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/ITaskStackListener.aidl \
|
||||
core/java/android/app/IBackupAgent.aidl \
|
||||
core/java/android/app/IEphemeralResolver.aidl \
|
||||
core/java/android/app/IInstantAppResolver.aidl \
|
||||
core/java/android/app/IInstrumentationWatcher.aidl \
|
||||
core/java/android/app/INotificationManager.aidl \
|
||||
core/java/android/app/IProcessObserver.aidl \
|
||||
|
||||
@@ -4662,16 +4662,12 @@ package android.app {
|
||||
field public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3; // 0x3
|
||||
}
|
||||
|
||||
public abstract class EphemeralResolverService extends android.app.Service {
|
||||
public abstract deprecated class EphemeralResolverService extends android.app.InstantAppResolverService {
|
||||
ctor public EphemeralResolverService();
|
||||
method public final void attachBaseContext(android.content.Context);
|
||||
method public android.os.Looper getLooper();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract deprecated java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int);
|
||||
method public android.content.pm.EphemeralResolveInfo onGetEphemeralIntentFilter(java.lang.String);
|
||||
method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralResolveInfo(int[]);
|
||||
field public static final java.lang.String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
|
||||
field public static final java.lang.String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
|
||||
}
|
||||
|
||||
public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
|
||||
@@ -4992,6 +4988,20 @@ package android.app {
|
||||
field public static final int TRANSIT_UNSET = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public abstract class InstantAppResolverService extends android.app.Service {
|
||||
ctor public InstantAppResolverService();
|
||||
method public final void attachBaseContext(android.content.Context);
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public void onGetInstantAppIntentFilter(int[], android.app.InstantAppResolverService.InstantAppResolutionCallback);
|
||||
method public void onGetInstantAppResolveInfo(int[], android.app.InstantAppResolverService.InstantAppResolutionCallback);
|
||||
field public static final java.lang.String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
|
||||
field public static final java.lang.String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
|
||||
}
|
||||
|
||||
public static final class InstantAppResolverService.InstantAppResolutionCallback {
|
||||
method public void onInstantAppResolveInfo(java.util.List<android.content.pm.InstantAppResolveInfo>);
|
||||
}
|
||||
|
||||
public class Instrumentation {
|
||||
ctor public Instrumentation();
|
||||
method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
|
||||
@@ -10528,7 +10538,7 @@ package android.content.pm {
|
||||
field public int reqTouchScreen;
|
||||
}
|
||||
|
||||
public final class EphemeralIntentFilter implements android.os.Parcelable {
|
||||
public final deprecated class EphemeralIntentFilter implements android.os.Parcelable {
|
||||
ctor public EphemeralIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
|
||||
method public int describeContents();
|
||||
method public java.util.List<android.content.IntentFilter> getFilters();
|
||||
@@ -10537,7 +10547,7 @@ package android.content.pm {
|
||||
field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralIntentFilter> CREATOR;
|
||||
}
|
||||
|
||||
public final class EphemeralResolveInfo implements android.os.Parcelable {
|
||||
public final deprecated class EphemeralResolveInfo implements android.os.Parcelable {
|
||||
ctor public deprecated EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
|
||||
ctor public deprecated EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>);
|
||||
ctor public EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>, int);
|
||||
@@ -10587,6 +10597,38 @@ package android.content.pm {
|
||||
field public int version;
|
||||
}
|
||||
|
||||
public final class InstantAppIntentFilter implements android.os.Parcelable {
|
||||
ctor public InstantAppIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
|
||||
method public int describeContents();
|
||||
method public java.util.List<android.content.IntentFilter> getFilters();
|
||||
method public java.lang.String getSplitName();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppIntentFilter> CREATOR;
|
||||
}
|
||||
|
||||
public final class InstantAppResolveInfo implements android.os.Parcelable {
|
||||
ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int);
|
||||
ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>);
|
||||
method public int describeContents();
|
||||
method public byte[] getDigestBytes();
|
||||
method public int getDigestPrefix();
|
||||
method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters();
|
||||
method public java.lang.String getPackageName();
|
||||
method public int getVersionCode();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
|
||||
field public static final java.lang.String SHA_ALGORITHM = "SHA-256";
|
||||
}
|
||||
|
||||
public static final class InstantAppResolveInfo.InstantAppDigest implements android.os.Parcelable {
|
||||
ctor public InstantAppResolveInfo.InstantAppDigest(java.lang.String);
|
||||
method public int describeContents();
|
||||
method public byte[][] getDigestBytes();
|
||||
method public int[] getDigestPrefix();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo.InstantAppDigest> CREATOR;
|
||||
}
|
||||
|
||||
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
|
||||
ctor public InstrumentationInfo();
|
||||
ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
/** @deprecated */
|
||||
parcelable EphemeralResolveInfo;
|
||||
|
||||
@@ -18,9 +18,11 @@ package android.app;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.app.InstantAppResolverService.InstantAppResolutionCallback;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.EphemeralResolveInfo;
|
||||
import android.content.pm.InstantAppResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -29,20 +31,17 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for implementing the resolver service.
|
||||
* @hide
|
||||
* @deprecated use InstantAppResolverService instead
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi
|
||||
public abstract class EphemeralResolverService extends Service {
|
||||
public static final String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
|
||||
public static final String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
|
||||
private static final String EXTRA_PREFIX = "android.app.PREFIX";
|
||||
private static final String EXTRA_HOSTNAME = "android.app.HOSTNAME";
|
||||
private Handler mHandler;
|
||||
|
||||
public abstract class EphemeralResolverService extends InstantAppResolverService {
|
||||
/**
|
||||
* Called to retrieve resolve info for ephemeral applications.
|
||||
*
|
||||
@@ -74,90 +73,28 @@ public abstract class EphemeralResolverService extends Service {
|
||||
throw new IllegalStateException("Must define");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Looper} to perform service operations on.
|
||||
*/
|
||||
@Override
|
||||
public Looper getLooper() {
|
||||
return getBaseContext().getMainLooper();
|
||||
return super.getLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
mHandler = new ServiceHandler(getLooper());
|
||||
void _onGetInstantAppResolveInfo(int[] digestPrefix, InstantAppResolutionCallback callback) {
|
||||
final List<EphemeralResolveInfo> response = onGetEphemeralResolveInfo(digestPrefix);
|
||||
final int responseSize = response == null ? 0 : response.size();
|
||||
final List<InstantAppResolveInfo> resultList = new ArrayList<>(responseSize);
|
||||
for (int i = 0; i < responseSize; i++) {
|
||||
resultList.add(response.get(i).getInstantAppResolveInfo());
|
||||
}
|
||||
callback.onInstantAppResolveInfo(resultList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return new IEphemeralResolver.Stub() {
|
||||
@Override
|
||||
public void getEphemeralResolveInfoList(
|
||||
IRemoteCallback callback, int digestPrefix[], int sequence) {
|
||||
final Message msg = mHandler.obtainMessage(
|
||||
ServiceHandler.MSG_GET_EPHEMERAL_RESOLVE_INFO, sequence, 0, callback);
|
||||
final Bundle data = new Bundle();
|
||||
data.putIntArray(EXTRA_PREFIX, digestPrefix);
|
||||
msg.setData(data);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getEphemeralIntentFilterList(
|
||||
IRemoteCallback callback, String hostName, int sequence) {
|
||||
final Message msg = mHandler.obtainMessage(
|
||||
ServiceHandler.MSG_GET_EPHEMERAL_INTENT_FILTER, sequence, 0, callback);
|
||||
final Bundle data = new Bundle();
|
||||
data.putString(EXTRA_HOSTNAME, hostName);
|
||||
msg.setData(data);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
public static final int MSG_GET_EPHEMERAL_RESOLVE_INFO = 1;
|
||||
public static final int MSG_GET_EPHEMERAL_INTENT_FILTER = 2;
|
||||
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper, null /*callback*/, true /*async*/);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleMessage(Message message) {
|
||||
final int action = message.what;
|
||||
switch (action) {
|
||||
case MSG_GET_EPHEMERAL_RESOLVE_INFO: {
|
||||
final IRemoteCallback callback = (IRemoteCallback) message.obj;
|
||||
final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX);
|
||||
final List<EphemeralResolveInfo> resolveInfo =
|
||||
onGetEphemeralResolveInfo(digestPrefix);
|
||||
final Bundle data = new Bundle();
|
||||
data.putInt(EXTRA_SEQUENCE, message.arg1);
|
||||
data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo);
|
||||
try {
|
||||
callback.sendResult(data);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case MSG_GET_EPHEMERAL_INTENT_FILTER: {
|
||||
final IRemoteCallback callback = (IRemoteCallback) message.obj;
|
||||
final String hostName = message.getData().getString(EXTRA_HOSTNAME);
|
||||
final EphemeralResolveInfo resolveInfo = onGetEphemeralIntentFilter(hostName);
|
||||
final Bundle data = new Bundle();
|
||||
data.putInt(EXTRA_SEQUENCE, message.arg1);
|
||||
data.putParcelable(EXTRA_RESOLVE_INFO, resolveInfo);
|
||||
try {
|
||||
callback.sendResult(data);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown message: " + action);
|
||||
}
|
||||
}
|
||||
}
|
||||
void _onGetInstantAppIntentFilter(int[] digestPrefix, String hostName,
|
||||
InstantAppResolutionCallback callback) {
|
||||
final EphemeralResolveInfo response = onGetEphemeralIntentFilter(hostName);
|
||||
final List<InstantAppResolveInfo> resultList = new ArrayList<>(1);
|
||||
resultList.add(response.getInstantAppResolveInfo());
|
||||
callback.onInstantAppResolveInfo(resultList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package android.app;
|
||||
|
||||
import android.os.IRemoteCallback;
|
||||
|
||||
/** @hide */
|
||||
/** @hide @deprecated */
|
||||
oneway interface IEphemeralResolver {
|
||||
void getEphemeralResolveInfoList(IRemoteCallback callback, in int[] digestPrefix,
|
||||
int sequence);
|
||||
|
||||
28
core/java/android/app/IInstantAppResolver.aidl
Normal file
28
core/java/android/app/IInstantAppResolver.aidl
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 android.app;
|
||||
|
||||
import android.os.IRemoteCallback;
|
||||
|
||||
/** @hide */
|
||||
oneway interface IInstantAppResolver {
|
||||
void getInstantAppResolveInfoList(in int[] digestPrefix,
|
||||
int sequence, IRemoteCallback callback);
|
||||
|
||||
void getInstantAppIntentFilterList(in int[] digestPrefix,
|
||||
int sequence, String hostName, IRemoteCallback callback);
|
||||
}
|
||||
19
core/java/android/app/InstantAppResolveInfo.aidl
Normal file
19
core/java/android/app/InstantAppResolveInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
** Copyright 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 android.app;
|
||||
|
||||
parcelable InstantAppResolveInfo;
|
||||
176
core/java/android/app/InstantAppResolverService.java
Normal file
176
core/java/android/app/InstantAppResolverService.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 android.app;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.InstantAppResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for implementing the resolver service.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class InstantAppResolverService extends Service {
|
||||
public static final String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
|
||||
public static final String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
|
||||
static final String EXTRA_PREFIX = "android.app.PREFIX";
|
||||
static final String EXTRA_HOSTNAME = "android.app.HOSTNAME";
|
||||
Handler mHandler;
|
||||
|
||||
/**
|
||||
* Called to retrieve resolve info for instant applications.
|
||||
*
|
||||
* @param digestPrefix The hash prefix of the instant app's domain.
|
||||
*/
|
||||
public void onGetInstantAppResolveInfo(
|
||||
int digestPrefix[], InstantAppResolutionCallback callback) {
|
||||
throw new IllegalStateException("Must define");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to retrieve intent filters for instant applications.
|
||||
*
|
||||
* @param digestPrefix The hash prefix of the instant app's domain.
|
||||
*/
|
||||
public void onGetInstantAppIntentFilter(
|
||||
int digestPrefix[], InstantAppResolutionCallback callback) {
|
||||
throw new IllegalStateException("Must define");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Looper} to perform service operations on.
|
||||
*/
|
||||
Looper getLooper() {
|
||||
return getBaseContext().getMainLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
mHandler = new ServiceHandler(getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return new IInstantAppResolver.Stub() {
|
||||
@Override
|
||||
public void getInstantAppResolveInfoList(
|
||||
int digestPrefix[], int sequence, IRemoteCallback callback) {
|
||||
final Message msg = mHandler.obtainMessage(
|
||||
ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO, sequence, 0, callback);
|
||||
final Bundle data = new Bundle();
|
||||
data.putIntArray(EXTRA_PREFIX, digestPrefix);
|
||||
msg.setData(data);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getInstantAppIntentFilterList(
|
||||
int digestPrefix[], int sequence, String hostName, IRemoteCallback callback) {
|
||||
final Message msg = mHandler.obtainMessage(
|
||||
ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER, sequence, 0, callback);
|
||||
final Bundle data = new Bundle();
|
||||
data.putString(EXTRA_HOSTNAME, hostName);
|
||||
data.putIntArray(EXTRA_PREFIX, digestPrefix);
|
||||
msg.setData(data);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to post results from instant app resolution.
|
||||
*/
|
||||
public static final class InstantAppResolutionCallback {
|
||||
private final IRemoteCallback mCallback;
|
||||
private final int mSequence;
|
||||
InstantAppResolutionCallback(int sequence, IRemoteCallback callback) {
|
||||
mCallback = callback;
|
||||
mSequence = sequence;
|
||||
}
|
||||
|
||||
public void onInstantAppResolveInfo(List<InstantAppResolveInfo> resolveInfo) {
|
||||
final Bundle data = new Bundle();
|
||||
data.putInt(EXTRA_SEQUENCE, mSequence);
|
||||
data.putParcelableList(EXTRA_RESOLVE_INFO, resolveInfo);
|
||||
try {
|
||||
mCallback.sendResult(data);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void _onGetInstantAppResolveInfo(int[] digestPrefix, InstantAppResolutionCallback callback) {
|
||||
onGetInstantAppResolveInfo(digestPrefix, callback);
|
||||
}
|
||||
@Deprecated
|
||||
void _onGetInstantAppIntentFilter(int digestPrefix[], String hostName,
|
||||
InstantAppResolutionCallback callback) {
|
||||
onGetInstantAppIntentFilter(digestPrefix, callback);
|
||||
}
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
public static final int MSG_GET_INSTANT_APP_RESOLVE_INFO = 1;
|
||||
public static final int MSG_GET_INSTANT_APP_INTENT_FILTER = 2;
|
||||
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper, null /*callback*/, true /*async*/);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleMessage(Message message) {
|
||||
final int action = message.what;
|
||||
switch (action) {
|
||||
case MSG_GET_INSTANT_APP_RESOLVE_INFO: {
|
||||
final IRemoteCallback callback = (IRemoteCallback) message.obj;
|
||||
final int sequence = message.arg1;
|
||||
final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX);
|
||||
_onGetInstantAppResolveInfo(
|
||||
digestPrefix, new InstantAppResolutionCallback(sequence, callback));
|
||||
} break;
|
||||
|
||||
case MSG_GET_INSTANT_APP_INTENT_FILTER: {
|
||||
final IRemoteCallback callback = (IRemoteCallback) message.obj;
|
||||
final int sequence = message.arg1;
|
||||
final int[] digestPrefix = message.getData().getIntArray(EXTRA_PREFIX);
|
||||
final String hostName = message.getData().getString(EXTRA_HOSTNAME);
|
||||
_onGetInstantAppIntentFilter(
|
||||
digestPrefix, hostName,
|
||||
new InstantAppResolutionCallback(sequence, callback));
|
||||
} break;
|
||||
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown message: " + action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,21 +31,21 @@ import android.content.IntentFilter;
|
||||
* @hide
|
||||
*/
|
||||
public final class AuxiliaryResolveInfo extends IntentFilter {
|
||||
/** Resolved information returned from the external ephemeral resolver */
|
||||
public final EphemeralResolveInfo resolveInfo;
|
||||
/** Resolved information returned from the external instant resolver */
|
||||
public final InstantAppResolveInfo resolveInfo;
|
||||
/** The resolved package. Copied from {@link #resolveInfo}. */
|
||||
public final String packageName;
|
||||
/** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
|
||||
public final String splitName;
|
||||
/** Whether or not ephemeral resolution needs the second phase */
|
||||
/** Whether or not instant resolution needs the second phase */
|
||||
public final boolean needsPhaseTwo;
|
||||
/** Opaque token to track the ephemeral application resolution */
|
||||
/** Opaque token to track the instant application resolution */
|
||||
public final String token;
|
||||
/** The version code of the package */
|
||||
public final int versionCode;
|
||||
|
||||
/** Create a response for installing an instant application. */
|
||||
public AuxiliaryResolveInfo(@NonNull EphemeralResolveInfo resolveInfo,
|
||||
public AuxiliaryResolveInfo(@NonNull InstantAppResolveInfo resolveInfo,
|
||||
@NonNull IntentFilter orig,
|
||||
@Nullable String splitName,
|
||||
@NonNull String token,
|
||||
|
||||
@@ -30,31 +30,34 @@ import java.util.List;
|
||||
* Information about an ephemeral application intent filter.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi
|
||||
public final class EphemeralIntentFilter implements Parcelable {
|
||||
private final String mSplitName;
|
||||
/** The filters used to match domain */
|
||||
private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
|
||||
private final InstantAppIntentFilter mInstantAppIntentFilter;
|
||||
|
||||
public EphemeralIntentFilter(@Nullable String splitName, @NonNull List<IntentFilter> filters) {
|
||||
if (filters == null || filters.size() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mSplitName = splitName;
|
||||
mFilters.addAll(filters);
|
||||
mInstantAppIntentFilter = new InstantAppIntentFilter(splitName, filters);
|
||||
}
|
||||
|
||||
EphemeralIntentFilter(@NonNull InstantAppIntentFilter intentFilter) {
|
||||
mInstantAppIntentFilter = intentFilter;
|
||||
}
|
||||
|
||||
EphemeralIntentFilter(Parcel in) {
|
||||
mSplitName = in.readString();
|
||||
in.readList(mFilters, null /*loader*/);
|
||||
mInstantAppIntentFilter = in.readParcelable(null /*loader*/);
|
||||
}
|
||||
|
||||
public String getSplitName() {
|
||||
return mSplitName;
|
||||
return mInstantAppIntentFilter.getSplitName();
|
||||
}
|
||||
|
||||
public List<IntentFilter> getFilters() {
|
||||
return mFilters;
|
||||
return mInstantAppIntentFilter.getFilters();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
InstantAppIntentFilter getInstantAppIntentFilter() {
|
||||
return mInstantAppIntentFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,33 +67,18 @@ public final class EphemeralIntentFilter implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(mSplitName);
|
||||
out.writeList(mFilters);
|
||||
out.writeParcelable(mInstantAppIntentFilter, flags);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<EphemeralIntentFilter> CREATOR
|
||||
= new Parcelable.Creator<EphemeralIntentFilter>() {
|
||||
@Override
|
||||
public EphemeralIntentFilter createFromParcel(Parcel in) {
|
||||
return new EphemeralIntentFilter(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EphemeralIntentFilter[] newArray(int size) {
|
||||
return new EphemeralIntentFilter[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
public static final class EphemeralResolveIntentInfo extends IntentFilter {
|
||||
private final EphemeralIntentFilter mResolveInfo;
|
||||
|
||||
public EphemeralResolveIntentInfo(@NonNull IntentFilter orig,
|
||||
@NonNull EphemeralIntentFilter resolveInfo) {
|
||||
super(orig);
|
||||
this.mResolveInfo = resolveInfo;
|
||||
}
|
||||
|
||||
public EphemeralIntentFilter getEphemeralResolveInfo() {
|
||||
return mResolveInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -34,18 +35,13 @@ import java.util.Locale;
|
||||
* Information about an ephemeral application.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi
|
||||
public final class EphemeralResolveInfo implements Parcelable {
|
||||
/** Algorithm that will be used to generate the domain digest */
|
||||
public static final String SHA_ALGORITHM = "SHA-256";
|
||||
|
||||
private final EphemeralDigest mDigest;
|
||||
private final String mPackageName;
|
||||
/** The filters used to match domain */
|
||||
private final List<EphemeralIntentFilter> mFilters;
|
||||
/** The version code of the app that this class resolves to */
|
||||
private final int mVersionCode;
|
||||
/** Filters only for legacy clients */
|
||||
private final InstantAppResolveInfo mInstantAppResolveInfo;
|
||||
@Deprecated
|
||||
private final List<IntentFilter> mLegacyFilters;
|
||||
|
||||
@@ -55,13 +51,12 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
if (uri == null || packageName == null || filters == null || filters.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mDigest = new EphemeralDigest(uri.getHost());
|
||||
mPackageName = packageName;
|
||||
mFilters = new ArrayList<EphemeralIntentFilter>();
|
||||
mFilters.add(new EphemeralIntentFilter(packageName, filters));
|
||||
final List<EphemeralIntentFilter> ephemeralFilters = new ArrayList<>(1);
|
||||
ephemeralFilters.add(new EphemeralIntentFilter(packageName, filters));
|
||||
mInstantAppResolveInfo = new InstantAppResolveInfo(uri.getHost(), packageName,
|
||||
createInstantAppIntentFilterList(ephemeralFilters));
|
||||
mLegacyFilters = new ArrayList<IntentFilter>(filters.size());
|
||||
mLegacyFilters.addAll(filters);
|
||||
mVersionCode = -1;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -71,22 +66,11 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
}
|
||||
|
||||
public EphemeralResolveInfo(@NonNull EphemeralDigest digest, @Nullable String packageName,
|
||||
@Nullable List<EphemeralIntentFilter> filters, int versionConde) {
|
||||
// validate arguments
|
||||
if ((packageName == null && (filters != null && filters.size() != 0))
|
||||
|| (packageName != null && (filters == null || filters.size() == 0))) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mDigest = digest;
|
||||
if (filters != null) {
|
||||
mFilters = new ArrayList<EphemeralIntentFilter>(filters.size());
|
||||
mFilters.addAll(filters);
|
||||
} else {
|
||||
mFilters = null;
|
||||
}
|
||||
@Nullable List<EphemeralIntentFilter> filters, int versionCode) {
|
||||
mInstantAppResolveInfo = new InstantAppResolveInfo(
|
||||
digest.getInstantAppDigest(), packageName,
|
||||
createInstantAppIntentFilterList(filters), versionCode);
|
||||
mLegacyFilters = null;
|
||||
mPackageName = packageName;
|
||||
mVersionCode = versionConde;
|
||||
}
|
||||
|
||||
public EphemeralResolveInfo(@NonNull String hostName, @Nullable String packageName,
|
||||
@@ -95,33 +79,53 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
}
|
||||
|
||||
EphemeralResolveInfo(Parcel in) {
|
||||
mDigest = in.readParcelable(null /*loader*/);
|
||||
mPackageName = in.readString();
|
||||
mFilters = new ArrayList<EphemeralIntentFilter>();
|
||||
in.readList(mFilters, null /*loader*/);
|
||||
mVersionCode = in.readInt();
|
||||
mInstantAppResolveInfo = in.readParcelable(null /*loader*/);
|
||||
mLegacyFilters = new ArrayList<IntentFilter>();
|
||||
in.readList(mLegacyFilters, null /*loader*/);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public InstantAppResolveInfo getInstantAppResolveInfo() {
|
||||
return mInstantAppResolveInfo;
|
||||
}
|
||||
|
||||
private static List<InstantAppIntentFilter> createInstantAppIntentFilterList(
|
||||
List<EphemeralIntentFilter> filters) {
|
||||
if (filters == null) {
|
||||
return null;
|
||||
}
|
||||
final int filterCount = filters.size();
|
||||
final List<InstantAppIntentFilter> returnList = new ArrayList<>(filterCount);
|
||||
for (int i = 0; i < filterCount; i++) {
|
||||
returnList.add(filters.get(i).getInstantAppIntentFilter());
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public byte[] getDigestBytes() {
|
||||
return mDigest.getDigestBytes()[0];
|
||||
return mInstantAppResolveInfo.getDigestBytes();
|
||||
}
|
||||
|
||||
public int getDigestPrefix() {
|
||||
return mDigest.getDigestPrefix()[0];
|
||||
return mInstantAppResolveInfo.getDigestPrefix();
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
return mInstantAppResolveInfo.getPackageName();
|
||||
}
|
||||
|
||||
public List<EphemeralIntentFilter> getIntentFilters() {
|
||||
return mFilters;
|
||||
final List<InstantAppIntentFilter> filters = mInstantAppResolveInfo.getIntentFilters();
|
||||
final int filterCount = filters.size();
|
||||
final List<EphemeralIntentFilter> returnList = new ArrayList<>(filterCount);
|
||||
for (int i = 0; i < filterCount; i++) {
|
||||
returnList.add(new EphemeralIntentFilter(filters.get(i)));
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public int getVersionCode() {
|
||||
return mVersionCode;
|
||||
return mInstantAppResolveInfo.getVersionCode();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -136,19 +140,17 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(mDigest, flags);
|
||||
out.writeString(mPackageName);
|
||||
out.writeList(mFilters);
|
||||
out.writeInt(mVersionCode);
|
||||
out.writeParcelable(mInstantAppResolveInfo, flags);
|
||||
out.writeList(mLegacyFilters);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR
|
||||
= new Parcelable.Creator<EphemeralResolveInfo>() {
|
||||
@Override
|
||||
public EphemeralResolveInfo createFromParcel(Parcel in) {
|
||||
return new EphemeralResolveInfo(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EphemeralResolveInfo[] newArray(int size) {
|
||||
return new EphemeralResolveInfo[size];
|
||||
}
|
||||
@@ -167,12 +169,7 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class EphemeralDigest implements Parcelable {
|
||||
private static final int DIGEST_MASK = 0xfffff000;
|
||||
private static final int DIGEST_PREFIX_COUNT = 5;
|
||||
/** Full digest of the domain hashes */
|
||||
private final byte[][] mDigestBytes;
|
||||
/** The first 4 bytes of the domain hashes */
|
||||
private final int[] mDigestPrefix;
|
||||
private final InstantAppDigest mInstantAppDigest;
|
||||
|
||||
public EphemeralDigest(@NonNull String hostName) {
|
||||
this(hostName, -1 /*maxDigests*/);
|
||||
@@ -180,73 +177,24 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
|
||||
/** @hide */
|
||||
public EphemeralDigest(@NonNull String hostName, int maxDigests) {
|
||||
if (hostName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests);
|
||||
mDigestPrefix = new int[mDigestBytes.length];
|
||||
for (int i = 0; i < mDigestBytes.length; i++) {
|
||||
mDigestPrefix[i] =
|
||||
((mDigestBytes[i][0] & 0xFF) << 24
|
||||
| (mDigestBytes[i][1] & 0xFF) << 16
|
||||
| (mDigestBytes[i][2] & 0xFF) << 8
|
||||
| (mDigestBytes[i][3] & 0xFF) << 0)
|
||||
& DIGEST_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[][] generateDigest(String hostName, int maxDigests) {
|
||||
ArrayList<byte[]> digests = new ArrayList<>();
|
||||
try {
|
||||
final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
|
||||
if (maxDigests <= 0) {
|
||||
final byte[] hostBytes = hostName.getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
} else {
|
||||
int prevDot = hostName.lastIndexOf('.');
|
||||
prevDot = hostName.lastIndexOf('.', prevDot - 1);
|
||||
// shortcut for short URLs
|
||||
if (prevDot < 0) {
|
||||
digests.add(digest.digest(hostName.getBytes()));
|
||||
} else {
|
||||
byte[] hostBytes =
|
||||
hostName.substring(prevDot + 1, hostName.length()).getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
int digestCount = 1;
|
||||
while (prevDot >= 0 && digestCount < maxDigests) {
|
||||
prevDot = hostName.lastIndexOf('.', prevDot - 1);
|
||||
hostBytes =
|
||||
hostName.substring(prevDot + 1, hostName.length()).getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
digestCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("could not find digest algorithm");
|
||||
}
|
||||
return digests.toArray(new byte[digests.size()][]);
|
||||
mInstantAppDigest = new InstantAppDigest(hostName, maxDigests);
|
||||
}
|
||||
|
||||
EphemeralDigest(Parcel in) {
|
||||
final int digestCount = in.readInt();
|
||||
if (digestCount == -1) {
|
||||
mDigestBytes = null;
|
||||
} else {
|
||||
mDigestBytes = new byte[digestCount][];
|
||||
for (int i = 0; i < digestCount; i++) {
|
||||
mDigestBytes[i] = in.createByteArray();
|
||||
}
|
||||
}
|
||||
mDigestPrefix = in.createIntArray();
|
||||
mInstantAppDigest = in.readParcelable(null /*loader*/);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
InstantAppDigest getInstantAppDigest() {
|
||||
return mInstantAppDigest;
|
||||
}
|
||||
|
||||
public byte[][] getDigestBytes() {
|
||||
return mDigestBytes;
|
||||
return mInstantAppDigest.getDigestBytes();
|
||||
}
|
||||
|
||||
public int[] getDigestPrefix() {
|
||||
return mDigestPrefix;
|
||||
return mInstantAppDigest.getDigestPrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -256,24 +204,17 @@ public final class EphemeralResolveInfo implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
if (mDigestBytes == null) {
|
||||
out.writeInt(-1);
|
||||
} else {
|
||||
out.writeInt(mDigestBytes.length);
|
||||
for (int i = 0; i < mDigestBytes.length; i++) {
|
||||
out.writeByteArray(mDigestBytes[i]);
|
||||
}
|
||||
}
|
||||
out.writeIntArray(mDigestPrefix);
|
||||
out.writeParcelable(mInstantAppDigest, flags);
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Parcelable.Creator<EphemeralDigest> CREATOR =
|
||||
new Parcelable.Creator<EphemeralDigest>() {
|
||||
@Override
|
||||
public EphemeralDigest createFromParcel(Parcel in) {
|
||||
return new EphemeralDigest(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EphemeralDigest[] newArray(int size) {
|
||||
return new EphemeralDigest[size];
|
||||
}
|
||||
|
||||
82
core/java/android/content/pm/InstantAppIntentFilter.java
Normal file
82
core/java/android/content/pm/InstantAppIntentFilter.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 android.content.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Information about an instant application intent filter.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class InstantAppIntentFilter implements Parcelable {
|
||||
private final String mSplitName;
|
||||
/** The filters used to match domain */
|
||||
private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
|
||||
|
||||
public InstantAppIntentFilter(@Nullable String splitName, @NonNull List<IntentFilter> filters) {
|
||||
if (filters == null || filters.size() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mSplitName = splitName;
|
||||
mFilters.addAll(filters);
|
||||
}
|
||||
|
||||
InstantAppIntentFilter(Parcel in) {
|
||||
mSplitName = in.readString();
|
||||
in.readList(mFilters, null /*loader*/);
|
||||
}
|
||||
|
||||
public String getSplitName() {
|
||||
return mSplitName;
|
||||
}
|
||||
|
||||
public List<IntentFilter> getFilters() {
|
||||
return mFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeString(mSplitName);
|
||||
out.writeList(mFilters);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<InstantAppIntentFilter> CREATOR
|
||||
= new Parcelable.Creator<InstantAppIntentFilter>() {
|
||||
@Override
|
||||
public InstantAppIntentFilter createFromParcel(Parcel in) {
|
||||
return new InstantAppIntentFilter(in);
|
||||
}
|
||||
@Override
|
||||
public InstantAppIntentFilter[] newArray(int size) {
|
||||
return new InstantAppIntentFilter[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -19,22 +19,22 @@ package android.content.pm;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Information needed to make an ephemeral application resolution request.
|
||||
* Information needed to make an instant application resolution request.
|
||||
* @hide
|
||||
*/
|
||||
public final class EphemeralRequest {
|
||||
/** Response from the first phase of ephemeral application resolution */
|
||||
public final class InstantAppRequest {
|
||||
/** Response from the first phase of instant application resolution */
|
||||
public final AuxiliaryResolveInfo responseObj;
|
||||
/** The original intent that triggered ephemeral application resolution */
|
||||
/** The original intent that triggered instant application resolution */
|
||||
public final Intent origIntent;
|
||||
/** Resolved type of the intent */
|
||||
public final String resolvedType;
|
||||
/** The name of the package requesting the ephemeral application */
|
||||
/** The name of the package requesting the instant application */
|
||||
public final String callingPackage;
|
||||
/** ID of the user requesting the ephemeral application */
|
||||
/** ID of the user requesting the instant application */
|
||||
public final int userId;
|
||||
|
||||
public EphemeralRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
|
||||
public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
|
||||
String resolvedType, String callingPackage, int userId) {
|
||||
this.responseObj = responseObj;
|
||||
this.origIntent = origIntent;
|
||||
250
core/java/android/content/pm/InstantAppResolveInfo.java
Normal file
250
core/java/android/content/pm/InstantAppResolveInfo.java
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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 android.content.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Information about an instant application.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class InstantAppResolveInfo implements Parcelable {
|
||||
/** Algorithm that will be used to generate the domain digest */
|
||||
public static final String SHA_ALGORITHM = "SHA-256";
|
||||
|
||||
private final InstantAppDigest mDigest;
|
||||
private final String mPackageName;
|
||||
/** The filters used to match domain */
|
||||
private final List<InstantAppIntentFilter> mFilters;
|
||||
/** The version code of the app that this class resolves to */
|
||||
private final int mVersionCode;
|
||||
|
||||
public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
|
||||
@Nullable List<InstantAppIntentFilter> filters, int versionConde) {
|
||||
// validate arguments
|
||||
if ((packageName == null && (filters != null && filters.size() != 0))
|
||||
|| (packageName != null && (filters == null || filters.size() == 0))) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mDigest = digest;
|
||||
if (filters != null) {
|
||||
mFilters = new ArrayList<InstantAppIntentFilter>(filters.size());
|
||||
mFilters.addAll(filters);
|
||||
} else {
|
||||
mFilters = null;
|
||||
}
|
||||
mPackageName = packageName;
|
||||
mVersionCode = versionConde;
|
||||
}
|
||||
|
||||
public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
|
||||
@Nullable List<InstantAppIntentFilter> filters) {
|
||||
this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/);
|
||||
}
|
||||
|
||||
InstantAppResolveInfo(Parcel in) {
|
||||
mDigest = in.readParcelable(null /*loader*/);
|
||||
mPackageName = in.readString();
|
||||
mFilters = new ArrayList<InstantAppIntentFilter>();
|
||||
in.readList(mFilters, null /*loader*/);
|
||||
mVersionCode = in.readInt();
|
||||
}
|
||||
|
||||
public byte[] getDigestBytes() {
|
||||
return mDigest.getDigestBytes()[0];
|
||||
}
|
||||
|
||||
public int getDigestPrefix() {
|
||||
return mDigest.getDigestPrefix()[0];
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
public List<InstantAppIntentFilter> getIntentFilters() {
|
||||
return mFilters;
|
||||
}
|
||||
|
||||
public int getVersionCode() {
|
||||
return mVersionCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(mDigest, flags);
|
||||
out.writeString(mPackageName);
|
||||
out.writeList(mFilters);
|
||||
out.writeInt(mVersionCode);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR
|
||||
= new Parcelable.Creator<InstantAppResolveInfo>() {
|
||||
public InstantAppResolveInfo createFromParcel(Parcel in) {
|
||||
return new InstantAppResolveInfo(in);
|
||||
}
|
||||
|
||||
public InstantAppResolveInfo[] newArray(int size) {
|
||||
return new InstantAppResolveInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class to generate and store each of the digests and prefixes
|
||||
* sent to the Instant App Resolver.
|
||||
* <p>
|
||||
* Since intent filters may want to handle multiple hosts within a
|
||||
* domain [eg “*.google.com”], the resolver is presented with multiple
|
||||
* hash prefixes. For example, "a.b.c.d.e" generates digests for
|
||||
* "d.e", "c.d.e", "b.c.d.e" and "a.b.c.d.e".
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class InstantAppDigest implements Parcelable {
|
||||
private static final int DIGEST_MASK = 0xfffff000;
|
||||
private static final int DIGEST_PREFIX_COUNT = 5;
|
||||
/** Full digest of the domain hashes */
|
||||
private final byte[][] mDigestBytes;
|
||||
/** The first 4 bytes of the domain hashes */
|
||||
private final int[] mDigestPrefix;
|
||||
|
||||
public InstantAppDigest(@NonNull String hostName) {
|
||||
this(hostName, -1 /*maxDigests*/);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public InstantAppDigest(@NonNull String hostName, int maxDigests) {
|
||||
if (hostName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests);
|
||||
mDigestPrefix = new int[mDigestBytes.length];
|
||||
for (int i = 0; i < mDigestBytes.length; i++) {
|
||||
mDigestPrefix[i] =
|
||||
((mDigestBytes[i][0] & 0xFF) << 24
|
||||
| (mDigestBytes[i][1] & 0xFF) << 16
|
||||
| (mDigestBytes[i][2] & 0xFF) << 8
|
||||
| (mDigestBytes[i][3] & 0xFF) << 0)
|
||||
& DIGEST_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[][] generateDigest(String hostName, int maxDigests) {
|
||||
ArrayList<byte[]> digests = new ArrayList<>();
|
||||
try {
|
||||
final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
|
||||
if (maxDigests <= 0) {
|
||||
final byte[] hostBytes = hostName.getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
} else {
|
||||
int prevDot = hostName.lastIndexOf('.');
|
||||
prevDot = hostName.lastIndexOf('.', prevDot - 1);
|
||||
// shortcut for short URLs
|
||||
if (prevDot < 0) {
|
||||
digests.add(digest.digest(hostName.getBytes()));
|
||||
} else {
|
||||
byte[] hostBytes =
|
||||
hostName.substring(prevDot + 1, hostName.length()).getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
int digestCount = 1;
|
||||
while (prevDot >= 0 && digestCount < maxDigests) {
|
||||
prevDot = hostName.lastIndexOf('.', prevDot - 1);
|
||||
hostBytes =
|
||||
hostName.substring(prevDot + 1, hostName.length()).getBytes();
|
||||
digests.add(digest.digest(hostBytes));
|
||||
digestCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("could not find digest algorithm");
|
||||
}
|
||||
return digests.toArray(new byte[digests.size()][]);
|
||||
}
|
||||
|
||||
InstantAppDigest(Parcel in) {
|
||||
final int digestCount = in.readInt();
|
||||
if (digestCount == -1) {
|
||||
mDigestBytes = null;
|
||||
} else {
|
||||
mDigestBytes = new byte[digestCount][];
|
||||
for (int i = 0; i < digestCount; i++) {
|
||||
mDigestBytes[i] = in.createByteArray();
|
||||
}
|
||||
}
|
||||
mDigestPrefix = in.createIntArray();
|
||||
}
|
||||
|
||||
public byte[][] getDigestBytes() {
|
||||
return mDigestBytes;
|
||||
}
|
||||
|
||||
public int[] getDigestPrefix() {
|
||||
return mDigestPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
if (mDigestBytes == null) {
|
||||
out.writeInt(-1);
|
||||
} else {
|
||||
out.writeInt(mDigestBytes.length);
|
||||
for (int i = 0; i < mDigestBytes.length; i++) {
|
||||
out.writeByteArray(mDigestBytes[i]);
|
||||
}
|
||||
}
|
||||
out.writeIntArray(mDigestPrefix);
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Parcelable.Creator<InstantAppDigest> CREATOR =
|
||||
new Parcelable.Creator<InstantAppDigest>() {
|
||||
@Override
|
||||
public InstantAppDigest createFromParcel(Parcel in) {
|
||||
return new InstantAppDigest(in);
|
||||
}
|
||||
@Override
|
||||
public InstantAppDigest[] newArray(int size) {
|
||||
return new InstantAppDigest[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ import android.view.Display;
|
||||
import com.android.internal.app.HeavyWeightSwitcherActivity;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
|
||||
import com.android.server.pm.EphemeralResolver;
|
||||
import com.android.server.pm.InstantAppResolver;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -526,10 +526,10 @@ class ActivityStarter {
|
||||
mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
|
||||
auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
|
||||
}
|
||||
return EphemeralResolver.buildEphemeralInstallerIntent(originalIntent,
|
||||
callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
|
||||
auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
|
||||
auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
|
||||
return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent,
|
||||
callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
|
||||
auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
|
||||
auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
|
||||
}
|
||||
|
||||
void postStartActivityProcessing(
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.app.EphemeralResolverService;
|
||||
import android.app.IEphemeralResolver;
|
||||
import android.app.IInstantAppResolver;
|
||||
import android.app.InstantAppResolverService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.EphemeralResolveInfo;
|
||||
import android.content.pm.InstantAppResolveInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -61,14 +61,14 @@ final class EphemeralResolverConnection {
|
||||
private final Intent mIntent;
|
||||
|
||||
private volatile boolean mBindRequested;
|
||||
private IEphemeralResolver mRemoteInstance;
|
||||
private IInstantAppResolver mRemoteInstance;
|
||||
|
||||
public EphemeralResolverConnection(Context context, ComponentName componentName) {
|
||||
mContext = context;
|
||||
mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
|
||||
}
|
||||
|
||||
public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(int hashPrefix[]) {
|
||||
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(int hashPrefix[]) {
|
||||
throwIfCalledOnMainThread();
|
||||
try {
|
||||
return mGetEphemeralResolveInfoCaller.getEphemeralResolveInfoList(
|
||||
@@ -83,24 +83,25 @@ final class EphemeralResolverConnection {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void getEphemeralIntentFilterList(String hostName, PhaseTwoCallback callback,
|
||||
Handler callbackHandler, final int sequence) {
|
||||
public final void getInstantAppIntentFilterList(int hashPrefix[], String hostName,
|
||||
PhaseTwoCallback callback, Handler callbackHandler, final int sequence) {
|
||||
final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() {
|
||||
@Override
|
||||
public void sendResult(Bundle data) throws RemoteException {
|
||||
final EphemeralResolveInfo ephemeralResolveInfo =
|
||||
data.getParcelable(EphemeralResolverService.EXTRA_RESOLVE_INFO);
|
||||
final ArrayList<InstantAppResolveInfo> resolveList =
|
||||
data.getParcelableArrayList(
|
||||
InstantAppResolverService.EXTRA_RESOLVE_INFO);
|
||||
callbackHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onPhaseTwoResolved(ephemeralResolveInfo, sequence);
|
||||
callback.onPhaseTwoResolved(resolveList, sequence);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
try {
|
||||
getRemoteInstanceLazy()
|
||||
.getEphemeralIntentFilterList(remoteCallback, hostName, sequence);
|
||||
.getInstantAppIntentFilterList(hashPrefix, sequence, hostName, remoteCallback);
|
||||
} catch (RemoteException re) {
|
||||
} catch (TimeoutException te) {
|
||||
}
|
||||
@@ -121,7 +122,7 @@ final class EphemeralResolverConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private IEphemeralResolver getRemoteInstanceLazy() throws TimeoutException {
|
||||
private IInstantAppResolver getRemoteInstanceLazy() throws TimeoutException {
|
||||
synchronized (mLock) {
|
||||
if (mRemoteInstance != null) {
|
||||
return mRemoteInstance;
|
||||
@@ -172,14 +173,15 @@ final class EphemeralResolverConnection {
|
||||
* Asynchronous callback when results come back from ephemeral resolution phase two.
|
||||
*/
|
||||
public abstract static class PhaseTwoCallback {
|
||||
abstract void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo, int sequence);
|
||||
abstract void onPhaseTwoResolved(
|
||||
List<InstantAppResolveInfo> instantAppResolveInfoList, int sequence);
|
||||
}
|
||||
|
||||
private final class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
synchronized (mLock) {
|
||||
mRemoteInstance = IEphemeralResolver.Stub.asInterface(service);
|
||||
mRemoteInstance = IInstantAppResolver.Stub.asInterface(service);
|
||||
mLock.notifyAll();
|
||||
}
|
||||
}
|
||||
@@ -193,7 +195,7 @@ final class EphemeralResolverConnection {
|
||||
}
|
||||
|
||||
private static final class GetEphemeralResolveInfoCaller
|
||||
extends TimedRemoteCaller<List<EphemeralResolveInfo>> {
|
||||
extends TimedRemoteCaller<List<InstantAppResolveInfo>> {
|
||||
private final IRemoteCallback mCallback;
|
||||
|
||||
public GetEphemeralResolveInfoCaller() {
|
||||
@@ -201,21 +203,21 @@ final class EphemeralResolverConnection {
|
||||
mCallback = new IRemoteCallback.Stub() {
|
||||
@Override
|
||||
public void sendResult(Bundle data) throws RemoteException {
|
||||
final ArrayList<EphemeralResolveInfo> resolveList =
|
||||
final ArrayList<InstantAppResolveInfo> resolveList =
|
||||
data.getParcelableArrayList(
|
||||
EphemeralResolverService.EXTRA_RESOLVE_INFO);
|
||||
InstantAppResolverService.EXTRA_RESOLVE_INFO);
|
||||
int sequence =
|
||||
data.getInt(EphemeralResolverService.EXTRA_SEQUENCE, -1);
|
||||
data.getInt(InstantAppResolverService.EXTRA_SEQUENCE, -1);
|
||||
onRemoteMethodResult(resolveList, sequence);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<EphemeralResolveInfo> getEphemeralResolveInfoList(
|
||||
IEphemeralResolver target, int hashPrefix[])
|
||||
public List<InstantAppResolveInfo> getEphemeralResolveInfoList(
|
||||
IInstantAppResolver target, int hashPrefix[])
|
||||
throws RemoteException, TimeoutException {
|
||||
final int sequence = onBeforeRemoteCall();
|
||||
target.getEphemeralResolveInfoList(mCallback, hashPrefix, sequence);
|
||||
target.getInstantAppResolveInfoList(hashPrefix, sequence, mCallback);
|
||||
return getResultTimed(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.EphemeralIntentFilter;
|
||||
import android.content.pm.EphemeralRequest;
|
||||
import android.content.pm.EphemeralResolveInfo;
|
||||
import android.content.pm.InstantAppRequest;
|
||||
import android.content.pm.AuxiliaryResolveInfo;
|
||||
import android.content.pm.EphemeralResolveInfo.EphemeralDigest;
|
||||
import android.content.pm.InstantAppIntentFilter;
|
||||
import android.content.pm.InstantAppResolveInfo;
|
||||
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
@@ -46,54 +46,52 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/** @hide */
|
||||
public abstract class EphemeralResolver {
|
||||
public static AuxiliaryResolveInfo doEphemeralResolutionPhaseOne(Context context,
|
||||
EphemeralResolverConnection connection, EphemeralRequest requestObj) {
|
||||
public abstract class InstantAppResolver {
|
||||
public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne(Context context,
|
||||
EphemeralResolverConnection connection, InstantAppRequest requestObj) {
|
||||
final Intent intent = requestObj.origIntent;
|
||||
final EphemeralDigest digest =
|
||||
new EphemeralDigest(intent.getData().getHost(), 5 /*maxDigests*/);
|
||||
final InstantAppDigest digest =
|
||||
new InstantAppDigest(intent.getData().getHost(), 5 /*maxDigests*/);
|
||||
final int[] shaPrefix = digest.getDigestPrefix();
|
||||
final List<EphemeralResolveInfo> ephemeralResolveInfoList =
|
||||
connection.getEphemeralResolveInfoList(shaPrefix);
|
||||
if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
|
||||
// No hash prefix match; there are no ephemeral apps for this domain.
|
||||
final List<InstantAppResolveInfo> instantAppResolveInfoList =
|
||||
connection.getInstantAppResolveInfoList(shaPrefix);
|
||||
if (instantAppResolveInfoList == null || instantAppResolveInfoList.size() == 0) {
|
||||
// No hash prefix match; there are no instant apps for this domain.
|
||||
return null;
|
||||
}
|
||||
|
||||
final String token = UUID.randomUUID().toString();
|
||||
return EphemeralResolver.filterEphemeralIntent(ephemeralResolveInfoList,
|
||||
return InstantAppResolver.filterInstantAppIntent(instantAppResolveInfoList,
|
||||
intent, requestObj.resolvedType, requestObj.userId,
|
||||
intent.getPackage(), digest, token);
|
||||
}
|
||||
|
||||
public static void doEphemeralResolutionPhaseTwo(Context context,
|
||||
EphemeralResolverConnection connection, EphemeralRequest requestObj,
|
||||
ActivityInfo ephemeralInstaller, Handler callbackHandler) {
|
||||
public static void doInstantAppResolutionPhaseTwo(Context context,
|
||||
EphemeralResolverConnection connection, InstantAppRequest requestObj,
|
||||
ActivityInfo instantAppInstaller, Handler callbackHandler) {
|
||||
final Intent intent = requestObj.origIntent;
|
||||
final String hostName = intent.getData().getHost();
|
||||
final EphemeralDigest digest = new EphemeralDigest(hostName, 5 /*maxDigests*/);
|
||||
final InstantAppDigest digest = new InstantAppDigest(hostName, 5 /*maxDigests*/);
|
||||
final int[] shaPrefix = digest.getDigestPrefix();
|
||||
|
||||
final PhaseTwoCallback callback = new PhaseTwoCallback() {
|
||||
@Override
|
||||
void onPhaseTwoResolved(EphemeralResolveInfo ephemeralResolveInfo,
|
||||
void onPhaseTwoResolved(List<InstantAppResolveInfo> instantAppResolveInfoList,
|
||||
int sequence) {
|
||||
final String packageName;
|
||||
final String splitName;
|
||||
final int versionCode;
|
||||
if (ephemeralResolveInfo != null) {
|
||||
final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList =
|
||||
new ArrayList<EphemeralResolveInfo>(1);
|
||||
ephemeralResolveInfoList.add(ephemeralResolveInfo);
|
||||
final AuxiliaryResolveInfo ephemeralIntentInfo =
|
||||
EphemeralResolver.filterEphemeralIntent(
|
||||
ephemeralResolveInfoList, intent, null /*resolvedType*/,
|
||||
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
|
||||
final AuxiliaryResolveInfo instantAppIntentInfo =
|
||||
InstantAppResolver.filterInstantAppIntent(
|
||||
instantAppResolveInfoList, intent, null /*resolvedType*/,
|
||||
0 /*userId*/, intent.getPackage(), digest,
|
||||
requestObj.responseObj.token);
|
||||
if (ephemeralIntentInfo != null
|
||||
&& ephemeralIntentInfo.resolveInfo != null) {
|
||||
packageName = ephemeralIntentInfo.resolveInfo.getPackageName();
|
||||
splitName = ephemeralIntentInfo.splitName;
|
||||
versionCode = ephemeralIntentInfo.resolveInfo.getVersionCode();
|
||||
if (instantAppIntentInfo != null
|
||||
&& instantAppIntentInfo.resolveInfo != null) {
|
||||
packageName = instantAppIntentInfo.resolveInfo.getPackageName();
|
||||
splitName = instantAppIntentInfo.splitName;
|
||||
versionCode = instantAppIntentInfo.resolveInfo.getVersionCode();
|
||||
} else {
|
||||
packageName = null;
|
||||
splitName = null;
|
||||
@@ -115,27 +113,27 @@ public abstract class EphemeralResolver {
|
||||
requestObj.responseObj.token,
|
||||
false /*needsPhaseTwo*/);
|
||||
installerIntent.setComponent(new ComponentName(
|
||||
ephemeralInstaller.packageName, ephemeralInstaller.name));
|
||||
instantAppInstaller.packageName, instantAppInstaller.name));
|
||||
context.startActivity(installerIntent);
|
||||
}
|
||||
};
|
||||
connection.getEphemeralIntentFilterList(
|
||||
hostName, callback, callbackHandler, 0 /*sequence*/);
|
||||
connection.getInstantAppIntentFilterList(
|
||||
shaPrefix, hostName, callback, callbackHandler, 0 /*sequence*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns an intent to launch the ephemeral installer.
|
||||
* Builds and returns an intent to launch the instant installer.
|
||||
*/
|
||||
public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
|
||||
@NonNull String callingPackage,
|
||||
@NonNull String resolvedType,
|
||||
int userId,
|
||||
@NonNull String ephemeralPackageName,
|
||||
@Nullable String ephemeralSplitName,
|
||||
@NonNull String instantAppPackageName,
|
||||
@Nullable String instantAppSplitName,
|
||||
int versionCode,
|
||||
@Nullable String token,
|
||||
boolean needsPhaseTwo) {
|
||||
// Construct the intent that launches the ephemeral installer
|
||||
// Construct the intent that launches the instant installer
|
||||
int flags = origIntent.getFlags();
|
||||
final Intent intent = new Intent();
|
||||
intent.setFlags(flags
|
||||
@@ -185,63 +183,63 @@ public abstract class EphemeralResolver {
|
||||
new IntentSender(successIntentTarget));
|
||||
} catch (RemoteException ignore) { /* ignore; same process */ }
|
||||
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackageName);
|
||||
intent.putExtra(Intent.EXTRA_SPLIT_NAME, ephemeralSplitName);
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName);
|
||||
intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
|
||||
intent.putExtra(Intent.EXTRA_VERSION_CODE, versionCode);
|
||||
}
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static AuxiliaryResolveInfo filterEphemeralIntent(
|
||||
List<EphemeralResolveInfo> ephemeralResolveInfoList,
|
||||
private static AuxiliaryResolveInfo filterInstantAppIntent(
|
||||
List<InstantAppResolveInfo> instantAppResolveInfoList,
|
||||
Intent intent, String resolvedType, int userId, String packageName,
|
||||
EphemeralDigest digest, String token) {
|
||||
InstantAppDigest digest, String token) {
|
||||
final int[] shaPrefix = digest.getDigestPrefix();
|
||||
final byte[][] digestBytes = digest.getDigestBytes();
|
||||
// Go in reverse order so we match the narrowest scope first.
|
||||
for (int i = shaPrefix.length - 1; i >= 0 ; --i) {
|
||||
for (EphemeralResolveInfo ephemeralInfo : ephemeralResolveInfoList) {
|
||||
if (!Arrays.equals(digestBytes[i], ephemeralInfo.getDigestBytes())) {
|
||||
for (InstantAppResolveInfo instantAppInfo : instantAppResolveInfoList) {
|
||||
if (!Arrays.equals(digestBytes[i], instantAppInfo.getDigestBytes())) {
|
||||
continue;
|
||||
}
|
||||
if (packageName != null
|
||||
&& !packageName.equals(ephemeralInfo.getPackageName())) {
|
||||
&& !packageName.equals(instantAppInfo.getPackageName())) {
|
||||
continue;
|
||||
}
|
||||
final List<EphemeralIntentFilter> ephemeralFilters =
|
||||
ephemeralInfo.getIntentFilters();
|
||||
final List<InstantAppIntentFilter> instantAppFilters =
|
||||
instantAppInfo.getIntentFilters();
|
||||
// No filters; we need to start phase two
|
||||
if (ephemeralFilters == null || ephemeralFilters.isEmpty()) {
|
||||
return new AuxiliaryResolveInfo(ephemeralInfo,
|
||||
if (instantAppFilters == null || instantAppFilters.isEmpty()) {
|
||||
return new AuxiliaryResolveInfo(instantAppInfo,
|
||||
new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
|
||||
null /*splitName*/, token, true /*needsPhase2*/);
|
||||
}
|
||||
// We have a domain match; resolve the filters to see if anything matches.
|
||||
final PackageManagerService.EphemeralIntentResolver ephemeralResolver =
|
||||
final PackageManagerService.EphemeralIntentResolver instantAppResolver =
|
||||
new PackageManagerService.EphemeralIntentResolver();
|
||||
for (int j = ephemeralFilters.size() - 1; j >= 0; --j) {
|
||||
final EphemeralIntentFilter ephemeralFilter = ephemeralFilters.get(j);
|
||||
final List<IntentFilter> splitFilters = ephemeralFilter.getFilters();
|
||||
for (int j = instantAppFilters.size() - 1; j >= 0; --j) {
|
||||
final InstantAppIntentFilter instantAppFilter = instantAppFilters.get(j);
|
||||
final List<IntentFilter> splitFilters = instantAppFilter.getFilters();
|
||||
if (splitFilters == null || splitFilters.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (int k = splitFilters.size() - 1; k >= 0; --k) {
|
||||
final AuxiliaryResolveInfo intentInfo =
|
||||
new AuxiliaryResolveInfo(ephemeralInfo,
|
||||
splitFilters.get(k), ephemeralFilter.getSplitName(),
|
||||
new AuxiliaryResolveInfo(instantAppInfo,
|
||||
splitFilters.get(k), instantAppFilter.getSplitName(),
|
||||
token, false /*needsPhase2*/);
|
||||
ephemeralResolver.addFilter(intentInfo);
|
||||
instantAppResolver.addFilter(intentInfo);
|
||||
}
|
||||
}
|
||||
List<AuxiliaryResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
|
||||
List<AuxiliaryResolveInfo> matchedResolveInfoList = instantAppResolver.queryIntent(
|
||||
intent, resolvedType, false /*defaultOnly*/, userId);
|
||||
if (!matchedResolveInfoList.isEmpty()) {
|
||||
return matchedResolveInfoList.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hash or filter mis-match; no ephemeral apps for this domain.
|
||||
// Hash or filter mis-match; no instant apps for this domain.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -128,8 +128,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.AppsQueryHelper;
|
||||
import android.content.pm.ChangedPackages;
|
||||
import android.content.pm.ComponentInfo;
|
||||
import android.content.pm.EphemeralRequest;
|
||||
import android.content.pm.EphemeralResolveInfo;
|
||||
import android.content.pm.InstantAppRequest;
|
||||
import android.content.pm.AuxiliaryResolveInfo;
|
||||
import android.content.pm.FallbackCategoryProvider;
|
||||
import android.content.pm.FeatureInfo;
|
||||
@@ -143,6 +142,7 @@ import android.content.pm.IPackageManager;
|
||||
import android.content.pm.IPackageMoveObserver;
|
||||
import android.content.pm.IPackageStatsObserver;
|
||||
import android.content.pm.InstantAppInfo;
|
||||
import android.content.pm.InstantAppResolveInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.IntentFilterVerificationInfo;
|
||||
import android.content.pm.KeySet;
|
||||
@@ -1736,9 +1736,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
break;
|
||||
}
|
||||
case INSTANT_APP_RESOLUTION_PHASE_TWO: {
|
||||
EphemeralResolver.doEphemeralResolutionPhaseTwo(mContext,
|
||||
InstantAppResolver.doInstantAppResolutionPhaseTwo(mContext,
|
||||
mInstantAppResolverConnection,
|
||||
(EphemeralRequest) msg.obj,
|
||||
(InstantAppRequest) msg.obj,
|
||||
mInstantAppInstallerActivity,
|
||||
mHandler);
|
||||
}
|
||||
@@ -5765,7 +5765,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Intent origIntent, String resolvedType, String callingPackage,
|
||||
int userId) {
|
||||
final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
|
||||
new EphemeralRequest(responseObj, origIntent, resolvedType,
|
||||
new InstantAppRequest(responseObj, origIntent, resolvedType,
|
||||
callingPackage, userId));
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
@@ -6296,11 +6296,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
if (addEphemeral) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
|
||||
final EphemeralRequest requestObject = new EphemeralRequest(
|
||||
final InstantAppRequest requestObject = new InstantAppRequest(
|
||||
null /*responseObj*/, intent /*origIntent*/, resolvedType,
|
||||
null /*callingPackage*/, userId);
|
||||
final AuxiliaryResolveInfo auxiliaryResponse =
|
||||
EphemeralResolver.doEphemeralResolutionPhaseOne(
|
||||
InstantAppResolver.doInstantAppResolutionPhaseOne(
|
||||
mContext, mInstantAppResolverConnection, requestObject);
|
||||
if (auxiliaryResponse != null) {
|
||||
if (DEBUG_EPHEMERAL) {
|
||||
@@ -12818,7 +12818,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
* would be needed to apply ordering. If the intent resolver becomes re-entrant,
|
||||
* this needs to be contained entirely within {@link #filterResults}.
|
||||
*/
|
||||
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
|
||||
final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = new ArrayMap<>();
|
||||
|
||||
@Override
|
||||
protected AuxiliaryResolveInfo[] newArray(int size) {
|
||||
@@ -12838,13 +12838,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
final String packageName = responseObj.resolveInfo.getPackageName();
|
||||
final Integer order = responseObj.getOrder();
|
||||
final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
|
||||
final Pair<Integer, InstantAppResolveInfo> lastOrderResult =
|
||||
mOrderResult.get(packageName);
|
||||
// ordering is enabled and this item's order isn't high enough
|
||||
if (lastOrderResult != null && lastOrderResult.first >= order) {
|
||||
return null;
|
||||
}
|
||||
final EphemeralResolveInfo res = responseObj.resolveInfo;
|
||||
final InstantAppResolveInfo res = responseObj.resolveInfo;
|
||||
if (order > 0) {
|
||||
// non-zero order, enable ordering
|
||||
mOrderResult.put(packageName, new Pair<>(order, res));
|
||||
@@ -12860,9 +12860,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
int resultSize = results.size();
|
||||
for (int i = 0; i < resultSize; i++) {
|
||||
final EphemeralResolveInfo info = results.get(i).resolveInfo;
|
||||
final InstantAppResolveInfo info = results.get(i).resolveInfo;
|
||||
final String packageName = info.getPackageName();
|
||||
final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
|
||||
final Pair<Integer, InstantAppResolveInfo> savedInfo = mOrderResult.get(packageName);
|
||||
if (savedInfo == null) {
|
||||
// package doesn't having ordering
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user