Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1047cba3 authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Added manifest metadata to define the content capture settings activity."

parents d0bcc39f a5d5e2db
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6448,6 +6448,7 @@ package android.service.contentcapture {
    method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
    method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
    field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
    field public static final String SERVICE_META_DATA = "android.content_capture";
  }
  public final class SnapshotData implements android.os.Parcelable {
+1 −0
Original line number Diff line number Diff line
@@ -2413,6 +2413,7 @@ package android.service.contentcapture {
    method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
    method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
    field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
    field public static final String SERVICE_META_DATA = "android.content_capture";
  }

  public final class SnapshotData implements android.os.Parcelable {
+15 −0
Original line number Diff line number Diff line
@@ -78,6 +78,21 @@ public abstract class ContentCaptureService extends Service {
    public static final String SERVICE_INTERFACE =
            "android.service.contentcapture.ContentCaptureService";

    /**
     * Name under which a ContentCaptureService component publishes information about itself.
     *
     * <p>This meta-data should reference an XML resource containing a
     * <code>&lt;{@link
     * android.R.styleable#ContentCaptureService content-capture-service}&gt;</code> tag.
     *
     * <p>This is a a sample XML file configuring a ContentCaptureService:
     * <pre> &lt;content-capture-service
     *     android:settingsActivity="foo.bar.SettingsActivity"
     *     . . .
     * /&gt;</pre>
     */
    public static final String SERVICE_META_DATA = "android.content_capture";

    private Handler mHandler;
    private IContentCaptureServiceCallback mCallback;

+171 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.service.contentcapture;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}.
 *
 * @hide
 */
public final class ContentCaptureServiceInfo {

    private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName();
    private static final String XML_TAG_SERVICE = "content-capture-service";

    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp,
            @UserIdInt int userId) throws PackageManager.NameNotFoundException {
        int flags = PackageManager.GET_META_DATA;
        if (!isTemp) {
            flags |= PackageManager.MATCH_SYSTEM_ONLY;
        }

        ServiceInfo si = null;
        try {
            si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
        } catch (RemoteException e) {
        }
        if (si == null) {
            throw new NameNotFoundException("Could not get serviceInfo for "
                    + (isTemp ? " (temp)" : "(default system)")
                    + " " + comp.flattenToShortString());
        }
        return si;
    }

    @NonNull
    private final ServiceInfo mServiceInfo;

    @Nullable
    private final String mSettingsActivity;

    public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp,
            boolean isTemporaryService, @UserIdInt int userId)
            throws PackageManager.NameNotFoundException {
        this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId));
    }

    private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) {
        // Check for permissions.
        if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
            Slog.w(TAG, "ContentCaptureService from '" + si.packageName
                    + "' does not require permission "
                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
            throw new SecurityException("Service does not require permission "
                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
        }

        mServiceInfo = si;

        // Get the metadata, if declared.
        final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(),
                ContentCaptureService.SERVICE_META_DATA);
        if (parser == null) {
            mSettingsActivity = null;
            return;
        }

        String settingsActivity = null;

        try {
            final Resources resources = context.getPackageManager().getResourcesForApplication(
                    si.applicationInfo);

            int type = 0;
            while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
                type = parser.next();
            }

            if (XML_TAG_SERVICE.equals(parser.getName())) {
                final AttributeSet allAttributes = Xml.asAttributeSet(parser);
                TypedArray afsAttributes = null;
                try {
                    afsAttributes = resources.obtainAttributes(allAttributes,
                            com.android.internal.R.styleable.ContentCaptureService);
                    settingsActivity = afsAttributes.getString(
                            R.styleable.ContentCaptureService_settingsActivity);
                } finally {
                    if (afsAttributes != null) {
                        afsAttributes.recycle();
                    }
                }
            } else {
                Log.e(TAG, "Meta-data does not start with content-capture-service tag");
            }
        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
            Log.e(TAG, "Error parsing auto fill service meta-data", e);
        }

        mSettingsActivity = settingsActivity;
    }

    public ServiceInfo getServiceInfo() {
        return mServiceInfo;
    }

    @Nullable
    public String getSettingsActivity() {
        return mSettingsActivity;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        builder.append(getClass().getSimpleName());
        builder.append("[").append(mServiceInfo);
        builder.append(", settings:").append(mSettingsActivity);
        return builder.toString();
    }

    /**
     * Dumps it!
     */
    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
        pw.print(prefix);
        pw.print("Component: ");
        pw.println(getServiceInfo().getComponentName());
        pw.print(prefix);
        pw.print("Settings: ");
        pw.println(mSettingsActivity);
    }
}
+18 −1
Original line number Diff line number Diff line
@@ -8108,7 +8108,7 @@

    <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a
         {@link android.service.autofill.AutofillService}, which is referenced from its
         {@link android.service.autofill#SERVICE_META_DATA} meta-data entry.
         {@link android.service.autofill.AutofillService#SERVICE_META_DATA} meta-data entry.
    -->
    <declare-styleable name="AutofillService">
        <!-- Fully qualified class name of an activity that allows the user to modify
@@ -8133,6 +8133,23 @@
        <attr name="maxLongVersionCode" format="string" />
    </declare-styleable>

    <!-- =============================== -->
    <!-- Content Capture attributes -->
    <!-- =============================== -->
    <eat-comment />

    <!-- Use <code>content-capture-service</code> as the root tag of the XML resource that describes
         a {@link android.service.contentcapture.ContentCaptureService}, which is referenced from
         its {@link android.service.contentcapture.ContentCaptureService#SERVICE_META_DATA}
         meta-data entry.
         @hide @SystemApi
    -->
    <declare-styleable name="ContentCaptureService">
        <!-- Fully qualified class name of an activity that allows the user to modify
             the settings for this service. -->
        <attr name="settingsActivity" />
    </declare-styleable>

    <!-- =============================== -->
    <!-- Contacts meta-data attributes -->
    <!-- =============================== -->
Loading