summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/res/layout/chooser_action_view.xml28
-rw-r--r--java/res/values/dimens.xml2
-rw-r--r--java/src/com/android/intentresolver/widget/ScrollableActionRow.kt120
3 files changed, 150 insertions, 0 deletions
diff --git a/java/res/layout/chooser_action_view.xml b/java/res/layout/chooser_action_view.xml
new file mode 100644
index 00000000..d74798e2
--- /dev/null
+++ b/java/res/layout/chooser_action_view.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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
+ -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="center"
+ android:drawablePadding="8dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="12sp"
+ android:maxWidth="192dp"
+ android:singleLine="true"
+ android:clickable="true"
+ android:drawableTint="?android:attr/textColorPrimary"
+ android:drawableTintMode="src_in"
+ style="?android:attr/borderlessButtonStyle"
+ />
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 2d6fe816..93cb4637 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -50,4 +50,6 @@
<dimen name="resolver_profile_tab_margin">4dp</dimen>
<dimen name="chooser_action_button_icon_size">18dp</dimen>
+ <dimen name="chooser_action_view_icon_size">22dp</dimen>
+ <dimen name="chooser_action_margin">0dp</dimen>
</resources>
diff --git a/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt
new file mode 100644
index 00000000..f3a34985
--- /dev/null
+++ b/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 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 com.android.intentresolver.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.intentresolver.R
+
+class ScrollableActionRow : RecyclerView, ActionRow {
+ constructor(context: Context) : this(context, null)
+ constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
+ constructor(
+ context: Context, attrs: AttributeSet?, defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr) {
+ layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+ adapter = Adapter(context)
+ }
+
+ private val actionsAdapter get() = adapter as Adapter
+
+ override fun setActions(actions: List<ActionRow.Action>) {
+ actionsAdapter.setActions(actions)
+ }
+
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ super.onLayout(changed, l, t, r, b)
+ setOverScrollMode(
+ if (areAllChildrenVisible) View.OVER_SCROLL_NEVER else View.OVER_SCROLL_ALWAYS
+ )
+ }
+
+ private val areAllChildrenVisible: Boolean
+ get() {
+ val count = getChildCount()
+ if (count == 0) return true
+ val first = getChildAt(0)
+ val last = getChildAt(count - 1)
+ return getChildAdapterPosition(first) == 0
+ && getChildAdapterPosition(last) == actionsAdapter.itemCount - 1
+ && isFullyVisible(first)
+ && isFullyVisible(last)
+ }
+
+ private fun isFullyVisible(view: View): Boolean =
+ view.left >= paddingLeft && view.right <= width - paddingRight
+
+ private class Adapter(private val context: Context) : RecyclerView.Adapter<ViewHolder>() {
+ private val iconSize: Int =
+ context.resources.getDimensionPixelSize(R.dimen.chooser_action_view_icon_size)
+ private val itemLayout = R.layout.chooser_action_view
+ private var actions: List<ActionRow.Action> = emptyList()
+
+ override fun onCreateViewHolder(parent: ViewGroup, type: Int): ViewHolder =
+ ViewHolder(
+ LayoutInflater.from(context).inflate(itemLayout, null) as TextView,
+ iconSize
+ )
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.bind(actions[position])
+ }
+
+ override fun getItemCount() = actions.size
+
+ override fun onViewRecycled(holder: ViewHolder) {
+ holder.unbind()
+ }
+
+ override fun onFailedToRecycleView(holder: ViewHolder): Boolean {
+ holder.unbind()
+ return super.onFailedToRecycleView(holder)
+ }
+
+ fun setActions(actions: List<ActionRow.Action>) {
+ this.actions = ArrayList(actions)
+ notifyDataSetChanged()
+ }
+ }
+
+ private class ViewHolder(
+ private val view: TextView, private val iconSize: Int
+ ) : RecyclerView.ViewHolder(view) {
+
+ fun bind(action: ActionRow.Action) {
+ if (action.icon != null) {
+ action.icon.setBounds(0, 0, iconSize, iconSize)
+ view.setCompoundDrawablesRelative(null, action.icon, null, null)
+ }
+ view.text = action.label ?: ""
+ view.setOnClickListener {
+ action.onClicked.run()
+ }
+ view.id = action.id
+ }
+
+ fun unbind() {
+ view.setOnClickListener(null)
+ }
+ }
+}