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

Commit 7827bc93 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "First version of SliceView (hidden for now)"

parents 071691f7 4575aa52
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -2099,7 +2099,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    public static Uri maybeAddUserId(Uri uri, int userId) {
    public static Uri maybeAddUserId(Uri uri, int userId) {
        if (uri == null) return null;
        if (uri == null) return null;
        if (userId != UserHandle.USER_CURRENT
        if (userId != UserHandle.USER_CURRENT
                && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
                && (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
                        || ContentResolver.SCHEME_SLICE.equals(uri.getScheme()))) {
            if (!uriHasUserId(uri)) {
            if (!uriHasUserId(uri)) {
                //We don't add the user Id if there's already one
                //We don't add the user Id if there's already one
                Uri.Builder builder = uri.buildUpon();
                Uri.Builder builder = uri.buildUpon();
+37 −1
Original line number Original line Diff line number Diff line
@@ -35,6 +35,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.widget.RemoteViews;
import android.widget.RemoteViews;


import com.android.internal.util.ArrayUtils;

import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;


@@ -136,7 +138,7 @@ public final class Slice implements Parcelable {
    }
    }


    /**
    /**
     * @return The Uri that this slice represents.
     * @return The Uri that this Slice represents.
     */
     */
    public Uri getUri() {
    public Uri getUri() {
        return mUri;
        return mUri;
@@ -190,6 +192,13 @@ public final class Slice implements Parcelable {
        return 0;
        return 0;
    }
    }


    /**
     * @hide
     */
    public boolean hasHint(@SliceHint String hint) {
        return ArrayUtils.contains(mHints, hint);
    }

    /**
    /**
     * A Builder used to construct {@link Slice}s
     * A Builder used to construct {@link Slice}s
     */
     */
@@ -308,4 +317,31 @@ public final class Slice implements Parcelable {
            return new Slice[size];
            return new Slice[size];
        }
        }
    };
    };

    /**
     * @hide
     * @return A string representation of this slice.
     */
    public String getString() {
        return getString("");
    }

    private String getString(String indent) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mItems.length; i++) {
            sb.append(indent);
            if (mItems[i].getType() == TYPE_SLICE) {
                sb.append("slice:\n");
                sb.append(mItems[i].getSlice().getString(indent + "   "));
            } else if (mItems[i].getType() == TYPE_TEXT) {
                sb.append("text: ");
                sb.append(mItems[i].getText());
                sb.append("\n");
            } else {
                sb.append(SliceItem.typeToString(mItems[i].getType()));
                sb.append("\n");
            }
        }
        return sb.toString();
    }
}
}
+34 −2
Original line number Original line Diff line number Diff line
@@ -132,6 +132,13 @@ public final class SliceItem implements Parcelable {
        mHints = ArrayUtils.appendElement(String.class, mHints, hint);
        mHints = ArrayUtils.appendElement(String.class, mHints, hint);
    }
    }


    /**
     * @hide
     */
    public void removeHint(String hint) {
        ArrayUtils.removeElement(String.class, mHints, hint);
    }

    public @SliceType int getType() {
    public @SliceType int getType() {
        return mType;
        return mType;
    }
    }
@@ -230,7 +237,7 @@ public final class SliceItem implements Parcelable {
    public boolean hasHints(@SliceHint String[] hints) {
    public boolean hasHints(@SliceHint String[] hints) {
        if (hints == null) return true;
        if (hints == null) return true;
        for (String hint : hints) {
        for (String hint : hints) {
            if (!ArrayUtils.contains(mHints, hint)) {
            if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
                return false;
                return false;
            }
            }
        }
        }
@@ -241,7 +248,7 @@ public final class SliceItem implements Parcelable {
     * @hide
     * @hide
     */
     */
    public boolean hasAnyHints(@SliceHint String[] hints) {
    public boolean hasAnyHints(@SliceHint String[] hints) {
        if (hints == null) return true;
        if (hints == null) return false;
        for (String hint : hints) {
        for (String hint : hints) {
            if (ArrayUtils.contains(mHints, hint)) {
            if (ArrayUtils.contains(mHints, hint)) {
                return true;
                return true;
@@ -309,4 +316,29 @@ public final class SliceItem implements Parcelable {
            return new SliceItem[size];
            return new SliceItem[size];
        }
        }
    };
    };

    /**
     * @hide
     */
    public static String typeToString(int type) {
        switch (type) {
            case TYPE_SLICE:
                return "Slice";
            case TYPE_TEXT:
                return "Text";
            case TYPE_IMAGE:
                return "Image";
            case TYPE_ACTION:
                return "Action";
            case TYPE_REMOTE_VIEW:
                return "RemoteView";
            case TYPE_COLOR:
                return "Color";
            case TYPE_TIMESTAMP:
                return "Timestamp";
            case TYPE_REMOTE_INPUT:
                return "RemoteInput";
        }
        return "Unrecognized type: " + type;
    }
}
}
+14 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,13 @@ public class SliceQuery {
        return stream(container).filter(s -> (s == item)).findAny().isPresent();
        return stream(container).filter(s -> (s == item)).findAny().isPresent();
    }
    }


    /**
     * @hide
     */
    public static List<SliceItem> findAll(SliceItem s, int type) {
        return findAll(s, type, (String[]) null, null);
    }

    /**
    /**
     * @hide
     * @hide
     */
     */
@@ -82,6 +89,13 @@ public class SliceQuery {
        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
        return find(s, type, new String[]{ hints }, new String[]{ nonHints });
    }
    }


    /**
     * @hide
     */
    public static SliceItem find(Slice s, int type) {
        return find(s, type, (String[]) null, null);
    }

    /**
    /**
     * @hide
     * @hide
     */
     */
+201 −0
Original line number Original line Diff line number Diff line
/*
 * 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.slice.views;

import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteInput;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.slice.Slice;
import android.slice.SliceItem;
import android.slice.SliceQuery;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * @hide
 */
public class ActionRow extends FrameLayout {

    private static final int MAX_ACTIONS = 5;
    private final int mSize;
    private final int mIconPadding;
    private final LinearLayout mActionsGroup;
    private final boolean mFullActions;
    private int mColor = Color.BLACK;

    public ActionRow(Context context, boolean fullActions) {
        super(context);
        mFullActions = fullActions;
        mSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
                context.getResources().getDisplayMetrics());
        mIconPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12,
                context.getResources().getDisplayMetrics());
        mActionsGroup = new LinearLayout(context);
        mActionsGroup.setOrientation(LinearLayout.HORIZONTAL);
        mActionsGroup.setLayoutParams(
                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        addView(mActionsGroup);
    }

    private void setColor(int color) {
        mColor = color;
        for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
            View view = mActionsGroup.getChildAt(i);
            SliceItem item = (SliceItem) view.getTag();
            boolean tint = !item.hasHint(Slice.HINT_NO_TINT);
            if (tint) {
                ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
            }
        }
    }

    private ImageView addAction(Icon icon, boolean allowTint, SliceItem image) {
        ImageView imageView = new ImageView(getContext());
        imageView.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
        imageView.setScaleType(ScaleType.FIT_CENTER);
        imageView.setImageIcon(icon);
        if (allowTint) {
            imageView.setImageTintList(ColorStateList.valueOf(mColor));
        }
        imageView.setBackground(SliceViewUtil.getDrawable(getContext(),
                android.R.attr.selectableItemBackground));
        imageView.setTag(image);
        addAction(imageView);
        return imageView;
    }

    /**
     * Set the actions and color for this action row.
     */
    public void setActions(SliceItem actionRow, SliceItem defColor) {
        removeAllViews();
        mActionsGroup.removeAllViews();
        addView(mActionsGroup);

        SliceItem color = SliceQuery.find(actionRow, SliceItem.TYPE_COLOR);
        if (color == null) {
            color = defColor;
        }
        if (color != null) {
            setColor(color.getColor());
        }
        SliceQuery.findAll(actionRow, SliceItem.TYPE_ACTION).forEach(action -> {
            if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
                return;
            }
            SliceItem image = SliceQuery.find(action, SliceItem.TYPE_IMAGE);
            if (image == null) {
                return;
            }
            boolean tint = !image.hasHint(Slice.HINT_NO_TINT);
            SliceItem input = SliceQuery.find(action, SliceItem.TYPE_REMOTE_INPUT);
            if (input != null && input.getRemoteInput().getAllowFreeFormInput()) {
                addAction(image.getIcon(), tint, image).setOnClickListener(
                        v -> handleRemoteInputClick(v, action.getAction(), input.getRemoteInput()));
                createRemoteInputView(mColor, getContext());
            } else {
                addAction(image.getIcon(), tint, image).setOnClickListener(v -> AsyncTask.execute(
                        () -> {
                            try {
                                action.getAction().send();
                            } catch (CanceledException e) {
                                e.printStackTrace();
                            }
                        }));
            }
        });
        setVisibility(getChildCount() != 0 ? View.VISIBLE : View.GONE);
    }

    private void addAction(View child) {
        mActionsGroup.addView(child, new LinearLayout.LayoutParams(mSize, mSize, 1));
    }

    private void createRemoteInputView(int color, Context context) {
        View riv = RemoteInputView.inflate(context, this);
        riv.setVisibility(View.INVISIBLE);
        addView(riv, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        riv.setBackgroundColor(color);
    }

    private boolean handleRemoteInputClick(View view, PendingIntent pendingIntent,
            RemoteInput input) {
        if (input == null) {
            return false;
        }

        ViewParent p = view.getParent().getParent();
        RemoteInputView riv = null;
        while (p != null) {
            if (p instanceof View) {
                View pv = (View) p;
                riv = findRemoteInputView(pv);
                if (riv != null) {
                    break;
                }
            }
            p = p.getParent();
        }
        if (riv == null) {
            return false;
        }

        int width = view.getWidth();
        if (view instanceof TextView) {
            // Center the reveal on the text which might be off-center from the TextView
            TextView tv = (TextView) view;
            if (tv.getLayout() != null) {
                int innerWidth = (int) tv.getLayout().getLineWidth(0);
                innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
                width = Math.min(width, innerWidth);
            }
        }
        int cx = view.getLeft() + width / 2;
        int cy = view.getTop() + view.getHeight() / 2;
        int w = riv.getWidth();
        int h = riv.getHeight();
        int r = Math.max(
                Math.max(cx + cy, cx + (h - cy)),
                Math.max((w - cx) + cy, (w - cx) + (h - cy)));

        riv.setRevealParameters(cx, cy, r);
        riv.setPendingIntent(pendingIntent);
        riv.setRemoteInput(new RemoteInput[] {
                input
        }, input);
        riv.focusAnimated();
        return true;
    }

    private RemoteInputView findRemoteInputView(View v) {
        if (v == null) {
            return null;
        }
        return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
    }
}
Loading