public class

ActionRow

extends FrameLayout

 java.lang.Object

↳FrameLayout

↳androidx.slice.widget.ActionRow

Gradle dependencies

compile group: 'androidx.slice', name: 'slice-view', version: '1.1.0-alpha02'

  • groupId: androidx.slice
  • artifactId: slice-view
  • version: 1.1.0-alpha02

Artifact androidx.slice:slice-view:1.1.0-alpha02 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.slice:slice-view com.android.support:slices-view

Summary

Constructors
publicActionRow(Context context, boolean fullActions)

Methods
public voidsetActions(java.util.List<SliceAction> actions, int color)

Set the actions and color for this action row.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ActionRow(Context context, boolean fullActions)

Methods

public void setActions(java.util.List<SliceAction> actions, int color)

Set the actions and color for this action row.

Source

/*
 * 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 androidx.slice.widget;

import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;

import static androidx.slice.core.SliceHints.ICON_IMAGE;

import android.app.PendingIntent.CanceledException;
import android.app.RemoteInput;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Build;
import android.util.Log;
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;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.graphics.drawable.IconCompat;
import androidx.core.widget.ImageViewCompat;
import androidx.slice.SliceItem;
import androidx.slice.core.SliceAction;
import androidx.slice.core.SliceActionImpl;
import androidx.slice.core.SliceQuery;

import java.util.List;

/**
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
public class ActionRow extends FrameLayout {

    private static final int MAX_ACTIONS = 5;
    private static final String TAG = "ActionRow";

    private final int mSize;
    private final int mIconPadding;
    private final LinearLayout mActionsGroup;
    private int mColor = Color.BLACK;

    public ActionRow(Context context, boolean fullActions) {
        super(context);
        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);
            int mode = (Integer) view.getTag();
            boolean tint = mode == ICON_IMAGE;
            if (tint) {
                ImageViewCompat.setImageTintList((ImageView) view, ColorStateList.valueOf(mColor));
            }
        }
    }

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

    /**
     * Set the actions and color for this action row.
     */
    public void setActions(@NonNull List<SliceAction> actions, int color) {
        removeAllViews();
        mActionsGroup.removeAllViews();
        addView(mActionsGroup);
        if (color != -1) {
            setColor(color);
        }
        for (final SliceAction action : actions) {
            if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
                return;
            }
            final SliceItem sliceItem = ((SliceActionImpl) action).getSliceItem();
            final SliceItem actionItem = ((SliceActionImpl) action).getActionItem();
            final SliceItem input = SliceQuery.find(sliceItem, FORMAT_REMOTE_INPUT);
            final SliceItem image = SliceQuery.find(sliceItem, FORMAT_IMAGE);
            if (input != null && image != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    handleSetRemoteInputActions(input, image, actionItem);
                } else {
                    Log.w(TAG, "Received RemoteInput on API <20 " + input);
                }
            } else if (action.getIcon() != null) {
                IconCompat iconItem = action.getIcon();
                if (iconItem != null && actionItem != null) {
                    boolean tint = action.getImageMode() == ICON_IMAGE;
                    addAction(iconItem, tint).setOnClickListener(
                            new OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    try {
                                        // TODO - should log events here
                                        actionItem.fireAction(null, null);
                                    } 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));
    }

    @RequiresApi(21)
    private void handleSetRemoteInputActions(final SliceItem input, SliceItem image,
            final SliceItem action) {
        if (input.getRemoteInput().getAllowFreeFormInput()) {
            boolean tint = !image.hasHint(HINT_NO_TINT);
            addAction(image.getIcon(), tint).setOnClickListener(
                    new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            handleRemoteInputClick(v, action,
                                    input.getRemoteInput());
                        }
                    });
            createRemoteInputView(mColor, getContext());
        }
    }

    @RequiresApi(21)
    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);
    }

    @RequiresApi(21)
    boolean handleRemoteInputClick(View view, SliceItem action,
            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.setAction(action);
        riv.setRemoteInput(new RemoteInput[] {
                input
        }, input);
        riv.focusAnimated();
        return true;
    }

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