Make tree fragment's expandable current view expand by default
This gives the user a clearer overview of the current state of the application, without having to expand all the tasks. Padding has been reduced to better utilize available screen space. The bring to front and remove buttons are currently always hidden. Test: Manual Change-Id: Ifcda0ff31fd5adb89a12ff6a024842c0e7a7ab29
This commit is contained in:
@@ -9,7 +9,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
|||||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||||
|
|
||||||
LOCAL_STATIC_ANDROID_LIBRARIES := \
|
LOCAL_STATIC_ANDROID_LIBRARIES := \
|
||||||
androidx.appcompat_appcompat
|
androidx.appcompat_appcompat \
|
||||||
|
androidx.recyclerview_recyclerview
|
||||||
|
|
||||||
LOCAL_USE_AAPT2 := true
|
LOCAL_USE_AAPT2 := true
|
||||||
|
|
||||||
|
|||||||
@@ -17,37 +17,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:paddingBottom="@dimen/medMargin"
|
|
||||||
android:paddingEnd="@dimen/fullMargin"
|
|
||||||
android:paddingLeft="@dimen/fullMargin"
|
|
||||||
android:paddingRight="@dimen/fullMargin"
|
|
||||||
android:paddingStart="@dimen/fullMargin"
|
|
||||||
android:paddingTop="@dimen/medMargin">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="@dimen/listIcon"
|
|
||||||
android:layout_height="@dimen/listIcon"
|
|
||||||
android:clipChildren="true">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/color_label"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:src="@drawable/label_background"
|
|
||||||
android:tint="@color/defaultTint" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/activity_label"
|
|
||||||
android:layout_width="@dimen/listLabelTextBox"
|
|
||||||
android:layout_height="@dimen/listLabelTextBox"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:text="@string/activity_label"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textAppearance="@style/medium"
|
|
||||||
android:textColor="@color/labelText"
|
|
||||||
android:textSize="@dimen/titleText" />
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/activity_name"
|
android:id="@+id/activity_name"
|
||||||
@@ -62,8 +32,8 @@
|
|||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/intent_button"
|
android:id="@+id/intent_button"
|
||||||
style="?android:attr/borderlessButtonStyle"
|
style="?android:attr/borderlessButtonStyle"
|
||||||
android:layout_width="@dimen/listIcon"
|
android:layout_width="@dimen/intentButtonSize"
|
||||||
android:layout_height="@dimen/listIcon"
|
android:layout_height="@dimen/intentButtonSize"
|
||||||
android:src="@drawable/info_icon"
|
android:src="@drawable/info_icon"
|
||||||
android:tint="@color/defaultTint"
|
android:tint="@color/defaultTint"
|
||||||
android:tooltipText="@string/intent_button_tooltip"
|
android:tooltipText="@string/intent_button_tooltip"
|
||||||
|
|||||||
@@ -28,16 +28,17 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/smallMargin"
|
android:layout_marginBottom="@dimen/smallMargin"
|
||||||
android:layout_marginStart="@dimen/medMargin"
|
android:layout_marginStart="@dimen/smallMargin"
|
||||||
android:layout_marginTop="@dimen/medMargin"
|
android:layout_marginTop="@dimen/medMargin"
|
||||||
android:text="@string/task_tree_title"
|
android:text="@string/task_tree_title"
|
||||||
android:textAppearance="@style/title" />
|
android:textAppearance="@style/title" />
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/task_tree"
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:divider="@drawable/divider"
|
android:id="@+id/tree_recycler">
|
||||||
android:showDividers="middle"/>
|
|
||||||
</LinearLayout>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
</LinearLayout>
|
||||||
|
|||||||
50
samples/IntentPlayground/res/layout/task_item.xml
Normal file
50
samples/IntentPlayground/res/layout/task_item.xml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2018 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/task_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/fullMargin"
|
||||||
|
android:text="@string/task_num"
|
||||||
|
android:textAppearance="@style/medium"
|
||||||
|
android:textSize="@dimen/regularText"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/task_id"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/placeholder"
|
||||||
|
android:textAppearance="@style/medium"
|
||||||
|
android:textSize="@dimen/regularText"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="end"
|
||||||
|
android:id="@+id/activity_node_container"/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:gravity="center_vertical|left"
|
android:gravity="center_vertical|left"
|
||||||
android:layout_height="@dimen/listItem" >
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/task_label"
|
android:id="@+id/task_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/fullMargin"
|
android:layout_marginStart="@dimen/smallMargin"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:text="@string/task_num"
|
android:text="@string/task_num"
|
||||||
android:textAppearance="@style/medium"
|
android:textAppearance="@style/medium"
|
||||||
@@ -46,11 +46,4 @@
|
|||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="@string/placeholder"
|
android:text="@string/placeholder"
|
||||||
android:textSize="@dimen/smallText" />
|
android:textSize="@dimen/smallText" />
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/group_indicator"
|
|
||||||
android:layout_width="@dimen/listControl"
|
|
||||||
android:layout_height="@dimen/listControl"
|
|
||||||
android:layout_marginEnd="@dimen/fullMargin"
|
|
||||||
android:src="@drawable/expand_more_mtrl" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -14,47 +14,69 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical" android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
<LinearLayout
|
android:orientation="vertical">
|
||||||
android:id="@+id/group_item"
|
|
||||||
android:layout_width="match_parent"
|
<LinearLayout
|
||||||
|
android:id="@+id/group_item"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/task_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical" />
|
android:layout_weight="0"
|
||||||
<LinearLayout
|
android:layout_marginStart="@dimen/smallMargin"
|
||||||
android:id="@+id/child_item"
|
android:text="@string/task_num"
|
||||||
android:layout_width="match_parent"
|
android:textAppearance="@style/medium"
|
||||||
|
android:textSize="@dimen/regularText"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/task_id"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_weight="0"
|
||||||
android:visibility="gone"
|
android:text="@string/placeholder"
|
||||||
android:paddingBottom="@dimen/medMargin" />
|
android:textAppearance="@style/medium"
|
||||||
|
android:textSize="@dimen/regularText"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/move_task_to_front_bar"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:id="@+id/activity_node_container"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/move_task_to_front_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="@dimen/smallMargin"
|
||||||
|
android:paddingStart="@dimen/smallMargin"
|
||||||
|
android:paddingEnd="@dimen/smallMargin"
|
||||||
|
android:gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/kill_task_button"
|
||||||
|
style="@style/flatButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:layout_weight="0"
|
||||||
android:orientation="horizontal"
|
android:text="@string/kill_task_button"/>
|
||||||
android:paddingBottom="@dimen/medMargin"
|
|
||||||
android:paddingEnd="@dimen/smallMargin"
|
|
||||||
android:paddingStart="@dimen/smallMargin"
|
|
||||||
android:visibility="gone" >
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/kill_task_button"
|
android:id="@+id/move_task_to_front_button"
|
||||||
style="@style/flatButton"
|
style="@style/flatButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:text="@string/kill_task_button" />
|
android:text="@string/move_to_front"/>
|
||||||
|
|
||||||
<Button
|
</LinearLayout>
|
||||||
android:id="@+id/move_task_to_front_button"
|
</LinearLayout>
|
||||||
style="@style/flatButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:text="@string/move_to_front" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
<dimen name="regularText">16sp</dimen>
|
<dimen name="regularText">16sp</dimen>
|
||||||
<dimen name="smallText">12sp</dimen>
|
<dimen name="smallText">12sp</dimen>
|
||||||
<dimen name="listItem">48dp</dimen>
|
<dimen name="listItem">48dp</dimen>
|
||||||
|
<dimen name="intentButtonSize">24dp</dimen>
|
||||||
<dimen name="denseListItem">40dp</dimen>
|
<dimen name="denseListItem">40dp</dimen>
|
||||||
<dimen name="listIcon">48dp</dimen>
|
<dimen name="listIcon">48dp</dimen>
|
||||||
<dimen name="listControl">24dp</dimen>
|
<dimen name="listControl">24dp</dimen>
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 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.example.android.intentplayground;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.BaseExpandableListAdapter;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A two-level adapter for tasks and the activities that they hold (represented by Node).
|
|
||||||
*/
|
|
||||||
class ExpandableAdapter extends BaseExpandableListAdapter {
|
|
||||||
private FragmentActivity mActivity;
|
|
||||||
private Node mTasks;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new ExpandableAdapter.
|
|
||||||
* @param activity The activity that holds this adapter.
|
|
||||||
* @param tasks The {@link Node} root of the task hierarchy.
|
|
||||||
*/
|
|
||||||
public ExpandableAdapter(FragmentActivity activity, Node tasks) {
|
|
||||||
mActivity = activity;
|
|
||||||
mTasks = tasks;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int getGroupCount() {
|
|
||||||
return mTasks.mChildren.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getChildrenCount(int group) {
|
|
||||||
return mTasks.mChildren.get(group).mChildren.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getGroup(int group) {
|
|
||||||
return mTasks.mChildren.get(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getChild(int group, int child) {
|
|
||||||
return mTasks.mChildren.get(group).mChildren.get(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasStableIds() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getGroupView(int group, boolean isExpanded, View view, ViewGroup parent) {
|
|
||||||
String numActivitiesText;
|
|
||||||
TaskViewHolder holder;
|
|
||||||
Node task = (Node) getGroup(group);
|
|
||||||
int nActivities = getChildrenCount(group);
|
|
||||||
switch (nActivities) {
|
|
||||||
case 0: numActivitiesText = mActivity.getString(R.string.no_activities_text);
|
|
||||||
break;
|
|
||||||
case 1: numActivitiesText = mActivity.getString(R.string.one_activity_text);
|
|
||||||
break;
|
|
||||||
default: numActivitiesText = String.format(Locale.ENGLISH,
|
|
||||||
mActivity.getString(R.string.plural_activities_text), nActivities);
|
|
||||||
}
|
|
||||||
if (view == null) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(this.mActivity);
|
|
||||||
view = inflater.inflate(R.layout.task_node,parent, false);
|
|
||||||
holder = new TaskViewHolder(view);
|
|
||||||
view.setTag(holder);
|
|
||||||
} else {
|
|
||||||
holder = (TaskViewHolder) view.getTag();
|
|
||||||
}
|
|
||||||
if (isExpanded) {
|
|
||||||
holder.indicatorImageView.setImageResource(R.drawable.expand_less_mtrl);
|
|
||||||
} else {
|
|
||||||
holder.indicatorImageView.setImageResource(R.drawable.expand_more_mtrl);
|
|
||||||
}
|
|
||||||
holder.taskIdTextView.setText(task.mTaskId == Node.NEW_TASK_ID ?
|
|
||||||
mActivity.getString(R.string.new_task) : String.valueOf(task.mTaskId));
|
|
||||||
holder.taskIdTextView.setTextColor(mActivity
|
|
||||||
.getResources().getColor(ColorManager.getColorForTask(task.mTaskId),
|
|
||||||
null /* theme */));
|
|
||||||
holder.numActivitiesTextView.setText(numActivitiesText);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getChildView(int group, int child, boolean lastChild, View view, ViewGroup parent) {
|
|
||||||
Node activity = (Node) getChild(group, child);
|
|
||||||
ActivityViewHolder holder;
|
|
||||||
if (view == null) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(mActivity);
|
|
||||||
view = inflater.inflate(R.layout.activity_node, parent, false /* attachToRoot */);
|
|
||||||
holder = new ActivityViewHolder(view);
|
|
||||||
view.setTag(holder);
|
|
||||||
} else {
|
|
||||||
holder = (ActivityViewHolder) view.getTag();
|
|
||||||
}
|
|
||||||
holder.activityNameTextView.setText(activity.mName.getShortClassName());
|
|
||||||
holder.activityNumTextView.setText(String.format(Locale.ENGLISH, "%d",
|
|
||||||
getChildrenCount(group) - child));
|
|
||||||
int color = mActivity.getResources()
|
|
||||||
.getColor(ColorManager.getColorForActivity(activity.mName), null /* theme */);
|
|
||||||
holder.labelImageView.setColorFilter(color);
|
|
||||||
holder.intentButtonView.setColorFilter(color);
|
|
||||||
holder.intentButtonView.setOnClickListener(clickedView -> {
|
|
||||||
Intent intent = ((Node) getChild(group, child)).getIntent();
|
|
||||||
List<String> flags;
|
|
||||||
if (intent != null) {
|
|
||||||
flags = FlagUtils.discoverFlags(intent);
|
|
||||||
if (flags.size() == 0) {
|
|
||||||
flags.add("None");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flags = Collections.singletonList("None");
|
|
||||||
}
|
|
||||||
showDialogWithFlags(activity.mName.getShortClassName(), flags);
|
|
||||||
});
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a dialog with a list.
|
|
||||||
* @param shortClassName The activity name and title of the dialog.
|
|
||||||
* @param flags The flags to list.
|
|
||||||
*/
|
|
||||||
private void showDialogWithFlags(String shortClassName, List<String> flags) {
|
|
||||||
FragmentTransaction transaction = mActivity.getSupportFragmentManager().beginTransaction();
|
|
||||||
IntentDialogFragment.newInstance(shortClassName, flags).show(transaction, "intentDialog");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildSelectable(int i, int i1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getGroupId(int group) {
|
|
||||||
return mTasks.mChildren.get(group).mTaskId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getChildId(int group, int child) {
|
|
||||||
return ((Node) getChild(group, child)).mName.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TaskViewHolder {
|
|
||||||
TextView taskIdTextView, numActivitiesTextView;
|
|
||||||
ImageView indicatorImageView;
|
|
||||||
|
|
||||||
TaskViewHolder(View view) {
|
|
||||||
indicatorImageView = view.findViewById(R.id.group_indicator);
|
|
||||||
taskIdTextView = view.findViewById(R.id.task_id);
|
|
||||||
numActivitiesTextView = view.findViewById(R.id.num_activities);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static class ActivityViewHolder {
|
|
||||||
TextView activityNameTextView, activityNumTextView;
|
|
||||||
ImageView labelImageView;
|
|
||||||
ImageButton intentButtonView;
|
|
||||||
|
|
||||||
ActivityViewHolder(View view) {
|
|
||||||
activityNameTextView = view.findViewById(R.id.activity_name);
|
|
||||||
activityNumTextView = view.findViewById(R.id.activity_label);
|
|
||||||
labelImageView = view.findViewById(R.id.color_label);
|
|
||||||
intentButtonView = view.findViewById(R.id.intent_button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.example.android.intentplayground;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.example.android.intentplayground.InlineAdapter.TaskViewHolder;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class InlineAdapter extends RecyclerView.Adapter<TaskViewHolder> {
|
||||||
|
|
||||||
|
private final List<Node> mTasks;
|
||||||
|
private FragmentActivity mActivity;
|
||||||
|
|
||||||
|
public InlineAdapter(Node tree, FragmentActivity activity) {
|
||||||
|
this.mActivity = activity;
|
||||||
|
this.mTasks = tree.mChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View task = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.tree_node_composite, parent, false);
|
||||||
|
return new TaskViewHolder(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull TaskViewHolder holder, int position) {
|
||||||
|
holder.setTask(mTasks.get(position), mActivity.getSupportFragmentManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mTasks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TaskViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private final TextView mTaskIdTextView;
|
||||||
|
private final LinearLayout mActivitiesLayout;
|
||||||
|
|
||||||
|
public TaskViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
mTaskIdTextView = itemView.findViewById(R.id.task_id);
|
||||||
|
mActivitiesLayout = itemView.findViewById(R.id.activity_node_container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTask(Node task, FragmentManager manager) {
|
||||||
|
mTaskIdTextView.setText(task.mTaskId == Node.NEW_TASK_ID
|
||||||
|
? mTaskIdTextView.getContext().getString(R.string.new_task)
|
||||||
|
: String.valueOf(task.mTaskId));
|
||||||
|
mTaskIdTextView.setTextColor(mTaskIdTextView.getContext()
|
||||||
|
.getResources().getColor(ColorManager.getColorForTask(task.mTaskId),
|
||||||
|
null /* theme */));
|
||||||
|
|
||||||
|
mActivitiesLayout.removeAllViews();
|
||||||
|
for (Node activity : task.mChildren) {
|
||||||
|
View activityView = LayoutInflater.from(mActivitiesLayout.getContext())
|
||||||
|
.inflate(R.layout.activity_node, mActivitiesLayout, false);
|
||||||
|
TextView activityName = activityView.findViewById(R.id.activity_name);
|
||||||
|
ImageButton intentButtonView = activityView.findViewById(R.id.intent_button);
|
||||||
|
|
||||||
|
activityName.setText(activity.mName.getShortClassName());
|
||||||
|
|
||||||
|
int color = activityView.getContext().getResources()
|
||||||
|
.getColor(ColorManager.getColorForActivity(activity.mName),
|
||||||
|
null /* theme */);
|
||||||
|
intentButtonView.setColorFilter(color);
|
||||||
|
intentButtonView.setOnClickListener(clickedView -> {
|
||||||
|
Intent intent = activity.getIntent();
|
||||||
|
List<String> flags;
|
||||||
|
if (intent != null) {
|
||||||
|
flags = FlagUtils.discoverFlags(intent);
|
||||||
|
if (flags.size() == 0) {
|
||||||
|
flags.add("None");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flags = Collections.singletonList("None");
|
||||||
|
}
|
||||||
|
showDialogWithFlags(manager, activity.mName.getShortClassName(), flags);
|
||||||
|
});
|
||||||
|
|
||||||
|
mActivitiesLayout.addView(activityView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog with a list.
|
||||||
|
*
|
||||||
|
* @param shortClassName The activity name and title of the dialog.
|
||||||
|
* @param flags The flags to list.
|
||||||
|
*/
|
||||||
|
private void showDialogWithFlags(FragmentManager manager,
|
||||||
|
String shortClassName, List<String> flags) {
|
||||||
|
IntentDialogFragment.newInstance(shortClassName, flags).show(manager, "intentDialog");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,15 +22,18 @@ import android.os.Bundle;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This fragment displays a hierarchy of tasks and activities in an expandable list.
|
* This fragment displays a hierarchy of tasks and activities in an expandable list.
|
||||||
*/
|
*/
|
||||||
public class TreeFragment extends Fragment {
|
public class TreeFragment extends Fragment {
|
||||||
|
|
||||||
public static final String TREE_NODE = "com.example.android.NODE_TREE";
|
public static final String TREE_NODE = "com.example.android.NODE_TREE";
|
||||||
public static final String FRAGMENT_TITLE = "com.example.android.TREE_FRAGMENT_TITLE";
|
public static final String FRAGMENT_TITLE = "com.example.android.TREE_FRAGMENT_TITLE";
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
@@ -40,7 +43,7 @@ public class TreeFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
mTree = args.getParcelable(TREE_NODE);
|
mTree = args.getParcelable(TREE_NODE);
|
||||||
@@ -54,81 +57,26 @@ public class TreeFragment extends Fragment {
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
mActivity = getActivity();
|
mActivity = getActivity();
|
||||||
LinearLayout treeLayout = (LinearLayout) getView();
|
LinearLayout treeLayout = (LinearLayout) getView();
|
||||||
LinearLayout treeView = treeLayout.findViewById(R.id.task_tree);
|
|
||||||
mContainer = treeView;
|
|
||||||
TextView titleView = treeLayout.findViewById(R.id.task_tree_title);
|
TextView titleView = treeLayout.findViewById(R.id.task_tree_title);
|
||||||
|
RecyclerView recyclerView = treeLayout.findViewById(R.id.tree_recycler);
|
||||||
if (mTitle != null) {
|
if (mTitle != null) {
|
||||||
titleView.setText(mTitle);
|
titleView.setText(mTitle);
|
||||||
}
|
}
|
||||||
if (mTree != null) {
|
if (mTree != null) {
|
||||||
displayHierarchy(mTree, treeView);
|
displayRecycler(mTree, recyclerView);
|
||||||
} else {
|
} else {
|
||||||
displayHierarchy(TestBase.describeTaskHierarchy(mActivity), treeView);
|
displayRecycler(TestBase.describeTaskHierarchy(mActivity), recyclerView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void displayRecycler(Node root, RecyclerView recyclerView) {
|
||||||
* Takes a Node and creates views corresponding to the task hierarchy
|
recyclerView.setHasFixedSize(true);
|
||||||
* @param tree a {@link Node} that models the task hierarchy
|
recyclerView.setNestedScrollingEnabled(false);
|
||||||
* @param container the {@link LinearLayout} in which to display them
|
InlineAdapter adapter = new InlineAdapter(root, getActivity());
|
||||||
*/
|
recyclerView.setAdapter(adapter);
|
||||||
protected void displayHierarchy(Node tree, LinearLayout container) {
|
recyclerView
|
||||||
ExpandableAdapter adapter = new ExpandableAdapter(getActivity(), tree);
|
.setLayoutManager(
|
||||||
View view;
|
new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
|
||||||
// fill container
|
|
||||||
container.removeAllViews();
|
|
||||||
for (int i = 0; i < adapter.getGroupCount(); i++) {
|
|
||||||
view = makeCompositeView(adapter, container, i);
|
|
||||||
if (view != null) container.addView(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private View makeCompositeView(ExpandableAdapter adapter, ViewGroup parent, int group) {
|
|
||||||
LayoutInflater inflater = getLayoutInflater();
|
|
||||||
LinearLayout compositeLayout = (LinearLayout) inflater
|
|
||||||
.inflate(R.layout.tree_node_composite, parent, false /* attachToRoot */);
|
|
||||||
LinearLayout parentLayout = compositeLayout.findViewById(R.id.group_item);
|
|
||||||
LinearLayout childLayout = compositeLayout.findViewById(R.id.child_item);
|
|
||||||
LinearLayout buttonBarlayout = compositeLayout.findViewById(R.id.move_task_to_front_bar);
|
|
||||||
if (adapter.getChildrenCount(group) == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
parentLayout.addView(adapter.getGroupView(group, false /* isExpanded */,
|
|
||||||
null /* convertView */, parent));
|
|
||||||
for (int i = 0; i < adapter.getChildrenCount(group); i++) {
|
|
||||||
childLayout.addView(adapter.getChildView(group, i, false /* isLastChild */,
|
|
||||||
null /* convertView */, parentLayout));
|
|
||||||
}
|
|
||||||
compositeLayout.setOnClickListener(view -> {
|
|
||||||
LinearLayout childView1 = view.findViewById(R.id.child_item);
|
|
||||||
childView1.setVisibility(childView1.getVisibility() == View.GONE ?
|
|
||||||
View.VISIBLE : View.GONE);
|
|
||||||
if (group > 0) {
|
|
||||||
buttonBarlayout.setVisibility(buttonBarlayout.getVisibility() == View.GONE ?
|
|
||||||
View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
parentLayout.removeAllViews();
|
|
||||||
parentLayout.addView(adapter.getGroupView(group,
|
|
||||||
!(childView1.getVisibility() == View.GONE), null /* convertView */, parent));
|
|
||||||
});
|
|
||||||
// Set a no-op childView click listener so the event doesn't bubble up to the composite view
|
|
||||||
childLayout.setOnClickListener(view -> {});
|
|
||||||
//Set onclick listener for button bar
|
|
||||||
int taskId = ((Node) adapter.getGroup(group)).mTaskId;
|
|
||||||
if (group == 0) {
|
|
||||||
// hide the button bar, it is the current task
|
|
||||||
buttonBarlayout.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
int color = mActivity.getResources()
|
|
||||||
.getColor(ColorManager.getColorForTask(taskId), null /* theme */);
|
|
||||||
Button moveTaskButton = buttonBarlayout.findViewById(R.id.move_task_to_front_button);
|
|
||||||
moveTaskButton.setOnClickListener(view -> moveTaskToFront(taskId));
|
|
||||||
moveTaskButton.setTextColor(color);
|
|
||||||
Button removeTaskButton = buttonBarlayout.findViewById(R.id.kill_task_button);
|
|
||||||
removeTaskButton.setOnClickListener(view -> removeTask(taskId));
|
|
||||||
removeTaskButton.setTextColor(color);
|
|
||||||
}
|
|
||||||
return compositeLayout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeTask(int taskId) {
|
private void removeTask(int taskId) {
|
||||||
@@ -148,11 +96,14 @@ public class TreeFragment extends Fragment {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand a task group to show its child activities.
|
* Expand a task group to show its child activities.
|
||||||
|
*
|
||||||
* @param i The index of the task to expand.
|
* @param i The index of the task to expand.
|
||||||
*/
|
*/
|
||||||
public void openTask(int i) {
|
public void openTask(int i) {
|
||||||
View taskView = mContainer.getChildAt(i);
|
View taskView = mContainer.getChildAt(i);
|
||||||
if (taskView != null) taskView.callOnClick();
|
if (taskView != null) {
|
||||||
|
taskView.callOnClick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user