11fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy/*
21fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Copyright (C) 2017 The Android Open Source Project
31fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy *
41fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Licensed under the Apache License, Version 2.0 (the "License");
51fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * you may not use this file except in compliance with the License.
61fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * You may obtain a copy of the License at
71fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy *
81fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy *      http://www.apache.org/licenses/LICENSE-2.0
91fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy *
101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Unless required by applicable law or agreed to in writing, software
111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * distributed under the License is distributed on an "AS IS" BASIS,
121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * See the License for the specific language governing permissions and
141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * limitations under the License.
151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy */
161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedypackage android.content.pm;
181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.NonNull;
201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.Nullable;
211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.SystemApi;
22577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumannimport android.content.Intent;
23709ee1551db935adb2026fae9dd799e60f784499Patrick Baumannimport android.os.Bundle;
241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.os.Parcel;
251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.os.Parcelable;
261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.security.MessageDigest;
281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.security.NoSuchAlgorithmException;
294db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.security.SecureRandom;
301fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.ArrayList;
314db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.util.Arrays;
32577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumannimport java.util.Collections;
331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.List;
341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.Locale;
354db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.util.Random;
361fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
371fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy/**
38577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * Describes an externally resolvable instant application. There are three states that this class
39577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * can represent: <p/>
40577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * <ul>
41577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     <li>
42577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         The first, usable only for non http/s intents, implies that the resolver cannot
43577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         immediately resolve this intent and would prefer that resolution be deferred to the
44577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         instant app installer. Represent this state with {@link #InstantAppResolveInfo(Bundle)}.
45577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         If the {@link android.content.Intent} has the scheme set to http/s and a set of digest
46577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         prefixes were passed into one of the resolve methods in
47577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         {@link android.app.InstantAppResolverService}, this state cannot be used.
48577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     </li>
49577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     <li>
50577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         The second represents a partial match and is constructed with any of the other
51577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         constructors. By setting one or more of the {@link Nullable}arguments to null, you
52577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         communicate to the resolver in response to
53577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         {@link android.app.InstantAppResolverService#onGetInstantAppResolveInfo(Intent, int[],
54577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *                String, InstantAppResolverService.InstantAppResolutionCallback)}
55577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         that you need a 2nd round of resolution to complete the request.
56577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     </li>
57577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     <li>
58577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         The third represents a complete match and is constructed with all @Nullable parameters
59577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *         populated.
60577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann *     </li>
61577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * </ul>
621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * @hide
631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy */
641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy@SystemApi
651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedypublic final class InstantAppResolveInfo implements Parcelable {
661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    /** Algorithm that will be used to generate the domain digest */
67877e979b108f4fde20c73035c125a445e5b23269Todd Kennedy    private static final String SHA_ALGORITHM = "SHA-256";
681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
69577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    private static final byte[] EMPTY_DIGEST = new byte[0];
70577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann
711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    private final InstantAppDigest mDigest;
721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    private final String mPackageName;
731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    /** The filters used to match domain */
741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    private final List<InstantAppIntentFilter> mFilters;
751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    /** The version code of the app that this class resolves to */
763accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    private final long mVersionCode;
77709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann    /** Data about the app that should be passed along to the Instant App installer on resolve */
78709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann    private final Bundle mExtras;
79577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    /**
80577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann     * A flag that indicates that the resolver is aware that an app may match, but would prefer
813abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * that the installer get the sanitized intent to decide.
82577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann     */
83577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    private final boolean mShouldLetInstallerDecide;
841fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
85577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    /** Constructor for intent-based InstantApp resolution results. */
861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
87c0dd03a666467d03e140f3a43704b3f3f3f4d4b7Todd Kennedy            @Nullable List<InstantAppIntentFilter> filters, int versionCode) {
88709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann        this(digest, packageName, filters, (long) versionCode, null /* extras */);
893accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    }
903accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn
91577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    /** Constructor for intent-based InstantApp resolution results with extras. */
923accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
93709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann            @Nullable List<InstantAppIntentFilter> filters, long versionCode,
94709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann            @Nullable Bundle extras) {
95577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        this(digest, packageName, filters, versionCode, extras, false);
96577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    }
97577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann
983abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    /** Constructor for intent-based InstantApp resolution results by hostname. */
993abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
1003abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann            @Nullable List<InstantAppIntentFilter> filters) {
1013abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann        this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/,
1023abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann                null /* extras */);
1033abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    }
1043abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann
1053abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    /**
1063abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * Constructor that indicates that resolution could be delegated to the installer when the
1073abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * sanitized intent contains enough information to resolve completely.
1083abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     */
1093abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    public InstantAppResolveInfo(@Nullable Bundle extras) {
1103abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann        this(InstantAppDigest.UNDEFINED, null, null, -1, extras, true);
1113abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    }
1123abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann
113577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    private InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
114577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            @Nullable List<InstantAppIntentFilter> filters, long versionCode,
115577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            @Nullable Bundle extras, boolean shouldLetInstallerDecide) {
1161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        // validate arguments
1171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        if ((packageName == null && (filters != null && filters.size() != 0))
1181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                || (packageName != null && (filters == null || filters.size() == 0))) {
1191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            throw new IllegalArgumentException();
1201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
1211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        mDigest = digest;
1221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        if (filters != null) {
123577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mFilters = new ArrayList<>(filters.size());
1241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            mFilters.addAll(filters);
1251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        } else {
1261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            mFilters = null;
1271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
1281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        mPackageName = packageName;
129c0dd03a666467d03e140f3a43704b3f3f3f4d4b7Todd Kennedy        mVersionCode = versionCode;
130709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann        mExtras = extras;
131577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        mShouldLetInstallerDecide = shouldLetInstallerDecide;
1321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    InstantAppResolveInfo(Parcel in) {
135577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        mShouldLetInstallerDecide = in.readBoolean();
136709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann        mExtras = in.readBundle();
137577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        if (mShouldLetInstallerDecide) {
138577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mDigest = InstantAppDigest.UNDEFINED;
139577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mPackageName = null;
140577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mFilters = Collections.emptyList();
141577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mVersionCode = -1;
142577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        } else {
143577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mDigest = in.readParcelable(null /*loader*/);
144577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mPackageName = in.readString();
145577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mFilters = new ArrayList<>();
146577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            in.readList(mFilters, null /*loader*/);
147577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            mVersionCode = in.readLong();
148577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        }
149577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    }
150577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann
1513abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann    /**
1523abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * Returns true if the resolver is aware that an app may match, but would prefer
1533abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * that the installer get the sanitized intent to decide. This should not be true for
1543abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     * resolutions that include a host and will be ignored in such cases.
1553abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann     */
156577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann    public boolean shouldLetInstallerDecide() {
157577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        return mShouldLetInstallerDecide;
1581fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1591fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1601fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public byte[] getDigestBytes() {
161577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        return mDigest.mDigestBytes.length > 0 ? mDigest.getDigestBytes()[0] : EMPTY_DIGEST;
1621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public int getDigestPrefix() {
1651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        return mDigest.getDigestPrefix()[0];
1661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public String getPackageName() {
1691fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        return mPackageName;
1701fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public List<InstantAppIntentFilter> getIntentFilters() {
1731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        return mFilters;
1741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1763accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    /**
1773accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn     * @deprecated Use {@link #getLongVersionCode} instead.
1783accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn     */
1793accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    @Deprecated
1801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public int getVersionCode() {
1813accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn        return (int) (mVersionCode & 0xffffffff);
1823accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    }
1833accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn
1843accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn    public long getLongVersionCode() {
1851fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        return mVersionCode;
1861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
188709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann    @Nullable
189709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann    public Bundle getExtras() {
190709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann        return mExtras;
191709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann    }
192709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann
1931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    @Override
1941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public int describeContents() {
1951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        return 0;
1961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
1971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
1981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    @Override
1991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public void writeToParcel(Parcel out, int flags) {
200577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        out.writeBoolean(mShouldLetInstallerDecide);
201577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        out.writeBundle(mExtras);
202577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        if (mShouldLetInstallerDecide) {
203577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            return;
204577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        }
2051fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        out.writeParcelable(mDigest, flags);
2061fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        out.writeString(mPackageName);
2071fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        out.writeList(mFilters);
2083accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn        out.writeLong(mVersionCode);
2091fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
2101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
2111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR
2121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            = new Parcelable.Creator<InstantAppResolveInfo>() {
2131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public InstantAppResolveInfo createFromParcel(Parcel in) {
2141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return new InstantAppResolveInfo(in);
2151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
2161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
2171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public InstantAppResolveInfo[] newArray(int size) {
2181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return new InstantAppResolveInfo[size];
2191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
2201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    };
2211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
2221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    /**
2231fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * Helper class to generate and store each of the digests and prefixes
2241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * sent to the Instant App Resolver.
2251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * <p>
2261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * Since intent filters may want to handle multiple hosts within a
2271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * domain [eg “*.google.com”], the resolver is presented with multiple
2281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * hash prefixes. For example, "a.b.c.d.e" generates digests for
2291fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * "d.e", "c.d.e", "b.c.d.e" and "a.b.c.d.e".
2301fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     *
2311fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     * @hide
2321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy     */
2331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    @SystemApi
2341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    public static final class InstantAppDigest implements Parcelable {
2354db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        static final int DIGEST_MASK = 0xfffff000;
2363abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann
2373abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann        /**
2383abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann         * A special instance that represents and undefined digest used for cases that a host was
2393abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann         * not provided or is irrelevant to the response.
2403abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann         */
241577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        public static final InstantAppDigest UNDEFINED =
242577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann                new InstantAppDigest(new byte[][]{}, new int[]{});
2434db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann
2444db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        private static Random sRandom = null;
2454db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        static {
2464db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            try {
2474db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                sRandom = SecureRandom.getInstance("SHA1PRNG");
2484db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            } catch (NoSuchAlgorithmException e) {
2494db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                // oh well
2504db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                sRandom = new Random();
2514db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            }
2524db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        }
2531fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        /** Full digest of the domain hashes */
2541fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        private final byte[][] mDigestBytes;
2554db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        /** The first 5 bytes of the domain hashes */
2561fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        private final int[] mDigestPrefix;
2574db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        /** The first 5 bytes of the domain hashes interspersed with random data */
2584db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        private int[] mDigestPrefixSecure;
2591fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
2601fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public InstantAppDigest(@NonNull String hostName) {
2611fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            this(hostName, -1 /*maxDigests*/);
2621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
2631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
2641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        /** @hide */
2651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public InstantAppDigest(@NonNull String hostName, int maxDigests) {
2661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            if (hostName == null) {
2671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                throw new IllegalArgumentException();
2681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
2691fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests);
2701fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            mDigestPrefix = new int[mDigestBytes.length];
2711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            for (int i = 0; i < mDigestBytes.length; i++) {
2721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                mDigestPrefix[i] =
2731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        ((mDigestBytes[i][0] & 0xFF) << 24
2741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                                | (mDigestBytes[i][1] & 0xFF) << 16
2751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                                | (mDigestBytes[i][2] & 0xFF) << 8
2761fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                                | (mDigestBytes[i][3] & 0xFF) << 0)
2771fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        & DIGEST_MASK;
2781fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
2791fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
2801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
281577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        private InstantAppDigest(byte[][] digestBytes, int[] prefix) {
282577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            this.mDigestPrefix = prefix;
283577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann            this.mDigestBytes = digestBytes;
284577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann        }
285577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann
2861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        private static byte[][] generateDigest(String hostName, int maxDigests) {
2871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            ArrayList<byte[]> digests = new ArrayList<>();
2881fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            try {
2891fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
2901fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                if (maxDigests <= 0) {
2911fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    final byte[] hostBytes = hostName.getBytes();
2921fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    digests.add(digest.digest(hostBytes));
2931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                } else {
2941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    int prevDot = hostName.lastIndexOf('.');
2951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    prevDot = hostName.lastIndexOf('.', prevDot - 1);
2961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    // shortcut for short URLs
2971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    if (prevDot < 0) {
2981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        digests.add(digest.digest(hostName.getBytes()));
2991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    } else {
3001fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        byte[] hostBytes =
3011fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                                hostName.substring(prevDot + 1, hostName.length()).getBytes();
3021fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        digests.add(digest.digest(hostBytes));
3031fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        int digestCount = 1;
3041fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        while (prevDot >= 0 && digestCount < maxDigests) {
3051fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                            prevDot = hostName.lastIndexOf('.', prevDot - 1);
3061fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                            hostBytes =
3071fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                                    hostName.substring(prevDot + 1, hostName.length()).getBytes();
3081fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                            digests.add(digest.digest(hostBytes));
3091fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                            digestCount++;
3101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                        }
3111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    }
3121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                }
3131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            } catch (NoSuchAlgorithmException e) {
3141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                throw new IllegalStateException("could not find digest algorithm");
3151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
3161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return digests.toArray(new byte[digests.size()][]);
3171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        InstantAppDigest(Parcel in) {
3201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            final int digestCount = in.readInt();
3211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            if (digestCount == -1) {
3221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                mDigestBytes = null;
3231fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            } else {
3241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                mDigestBytes = new byte[digestCount][];
3251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                for (int i = 0; i < digestCount; i++) {
3261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    mDigestBytes[i] = in.createByteArray();
3271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                }
3281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
3291fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            mDigestPrefix = in.createIntArray();
3304db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            mDigestPrefixSecure = in.createIntArray();
3311fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public byte[][] getDigestBytes() {
3341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return mDigestBytes;
3351fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3361fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3371fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public int[] getDigestPrefix() {
3381fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return mDigestPrefix;
3391fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3401fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3414db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        /**
3424db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann         * Returns a digest prefix with additional random prefixes interspersed.
3434db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann         * @hide
3444db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann         */
3454db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        public int[] getDigestPrefixSecure() {
3464db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            if (this == InstantAppResolveInfo.InstantAppDigest.UNDEFINED) {
3474db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                return getDigestPrefix();
3484db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            } else if (mDigestPrefixSecure == null) {
3494db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                // let's generate some random data to intersperse throughout the set of prefixes
3504db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                final int realSize = getDigestPrefix().length;
3514db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                final int manufacturedSize = realSize + 10 + sRandom.nextInt(10);
3524db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                mDigestPrefixSecure = Arrays.copyOf(getDigestPrefix(), manufacturedSize);
3534db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                for (int i = realSize; i < manufacturedSize; i++) {
3544db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                    mDigestPrefixSecure[i] = sRandom.nextInt() & DIGEST_MASK;
3554db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                }
3564db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                Arrays.sort(mDigestPrefixSecure);
3574db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            }
3584db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            return mDigestPrefixSecure;
3594db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann        }
3604db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann
3611fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        @Override
3621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public int describeContents() {
3631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            return 0;
3641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        @Override
3671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public void writeToParcel(Parcel out, int flags) {
3684db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            final boolean isUndefined = this == UNDEFINED;
3694db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            out.writeBoolean(isUndefined);
3704db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            if (isUndefined) {
3714db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                return;
3724db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            }
3731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            if (mDigestBytes == null) {
3741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                out.writeInt(-1);
3751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            } else {
3761fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                out.writeInt(mDigestBytes.length);
3771fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                for (int i = 0; i < mDigestBytes.length; i++) {
3781fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                    out.writeByteArray(mDigestBytes[i]);
3791fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                }
3801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
3811fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            out.writeIntArray(mDigestPrefix);
3824db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann            out.writeIntArray(mDigestPrefixSecure);
3831fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        }
3841fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy
3851fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        @SuppressWarnings("hiding")
3861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        public static final Parcelable.Creator<InstantAppDigest> CREATOR =
3871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                new Parcelable.Creator<InstantAppDigest>() {
3881fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            @Override
3891fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            public InstantAppDigest createFromParcel(Parcel in) {
3904db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                if (in.readBoolean() /* is undefined */) {
3914db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                    return UNDEFINED;
3924db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann                }
3931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                return new InstantAppDigest(in);
3941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
3951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            @Override
3961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            public InstantAppDigest[] newArray(int size) {
3971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy                return new InstantAppDigest[size];
3981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy            }
3991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy        };
4001fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy    }
4011fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy}
402