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

Commit 4e5fb2f4 authored by Winson Chung's avatar Winson Chung
Browse files

Allowing tasks to be swiped away in the history view.

Change-Id: Ide26856c291bcdd1b4ab5e15ae9eb876a9af719b
parent b169ebd4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ public class Constants {
        public static final int DismissSourceKeyboard = 0;
        public static final int DismissSourceSwipeGesture = 1;
        public static final int DismissSourceHeaderButton = 2;
        public static final int DismissSourceHistorySwipeGesture = 3;
    }

}
+2 −1
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DismissTaskEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
@@ -726,7 +727,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
        MetricsLogger.count(this, "overview_app_info", 1);
    }

    public final void onBusEvent(DismissTaskViewEvent event) {
    public final void onBusEvent(DismissTaskEvent event) {
        // Remove any stored data from the loader
        RecentsTaskLoader loader = Recents.getTaskLoader();
        loader.deleteTaskData(event.task, false);
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.systemui.recents.events.ui;

import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.TaskView;

/**
 * This is sent when a {@link Task} has been dismissed.
 */
public class DismissTaskEvent extends EventBus.Event {

    public final Task task;

    public DismissTaskEvent(Task task) {
        this.task = task;
    }
}
+91 −23
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.ActivityOptions;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateFormat;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -27,9 +28,14 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;

import java.util.ArrayList;
import java.util.Calendar;
@@ -85,14 +91,14 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
    /**
     * A single row of content.
     */
    private interface Row {
    interface Row {
        int getViewType();
    }

    /**
     * A date row.
     */
    private static class DateRow implements Row {
    static class DateRow implements Row {

        public final String date;

@@ -109,12 +115,14 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
    /**
     * A task row.
     */
    private static class TaskRow implements Row, View.OnClickListener {
    static class TaskRow implements Row, View.OnClickListener {

        public final Task task;
        public final int dateKey;

        public TaskRow(Task task) {
        public TaskRow(Task task, int dateKey) {
            this.task = task;
            this.dateKey = dateKey;
        }

        @Override
@@ -134,6 +142,8 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
    private LayoutInflater mLayoutInflater;
    private final List<Task> mTasks = new ArrayList<>();
    private final List<Row> mRows = new ArrayList<>();
    private final SparseIntArray mTaskRowCount = new SparseIntArray();
    private TaskStack mStack;

    public RecentsHistoryAdapter(Context context) {
        mLayoutInflater = LayoutInflater.from(context);
@@ -142,17 +152,17 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
    /**
     * Updates this adapter with the given tasks.
     */
    public void updateTasks(Context context, List<Task> tasks) {
    public void updateTasks(Context context, TaskStack stack) {
        mContext = context;
        mTasks.clear();
        mTasks.addAll(tasks);
        mStack = stack;

        final Locale l = context.getResources().getConfiguration().locale;
        final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
        final List<Task> tasksMostRecent = new ArrayList<>(tasks);
        final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
        Collections.reverse(tasksMostRecent);
        int prevDayKey = -1;
        int prevDateKey = -1;
        mRows.clear();
        mTaskRowCount.clear();
        for (Task task : tasksMostRecent) {
            if (task.isFreeformTask()) {
                continue;
@@ -160,32 +170,44 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd

            Calendar cal = Calendar.getInstance(l);
            cal.setTimeInMillis(task.key.lastActiveTime);
            int dayKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
            if (dayKey != prevDayKey) {
                prevDayKey = dayKey;
            int dateKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
            if (dateKey != prevDateKey) {
                prevDateKey = dateKey;
                mRows.add(new DateRow(DateFormat.format(dateFormatStr, cal).toString()));
            }
            mRows.add(new TaskRow(task));
            mRows.add(new TaskRow(task, dateKey));
            mTaskRowCount.put(dateKey, mTaskRowCount.get(dateKey, 0) + 1);
        }
        notifyDataSetChanged();
    }

    /**
     * Removes historical tasks beloning to the specified package and user.
     * Removes historical tasks belonging to the specified package and user. We do not need to
     * remove the task from the TaskStack since the TaskStackView will also receive this event.
     */
    public void removeTasks(String packageName, int userId) {
        boolean packagesRemoved = false;
        for (int i = mTasks.size() - 1; i >= 0; i--) {
            Task task = mTasks.get(i);
        for (int i = mRows.size() - 1; i >= 0; i--) {
            Row row = mRows.get(i);
            if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
                TaskRow taskRow = (TaskRow) row;
                Task task = taskRow.task;
                String taskPackage = task.key.getComponent().getPackageName();
                if (task.key.userId == userId && taskPackage.equals(packageName)) {
                mTasks.remove(i);
                packagesRemoved = true;
                    i = removeTaskRow(i);
                }
            }
        }
        if (mRows.isEmpty()) {
            dismissHistory();
        }
        if (packagesRemoved) {
            updateTasks(mContext, new ArrayList<Task>(mTasks));
    }

    /**
     * Returns the row at the given {@param position}.
     */
    public Row getRow(int position) {
        return mRows.get(position);
    }

    @Override
@@ -242,6 +264,16 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
        }
    }

    public void onTaskRemoved(Task task, int position) {
        // Since this is removed from the history, we need to update the stack as well to ensure
        // that the model is correct
        mStack.removeTask(task);
        removeTaskRow(position);
        if (mRows.isEmpty()) {
            dismissHistory();
        }
    }

    @Override
    public int getItemCount() {
        return mRows.size();
@@ -251,4 +283,40 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
    public int getItemViewType(int position) {
        return mRows.get(position).getViewType();
    }

    /**
     * Removes a task row, also removing the associated {@link DateRow} if there are no more tasks
     * in that date group.
     *
     * @param position an adapter position of a task row such that 0 < position < num rows.
     * @return the index of the last removed row
     */
    private int removeTaskRow(int position) {
        // Remove the task at that row
        TaskRow taskRow = (TaskRow) mRows.remove(position);
        int numTasks = mTaskRowCount.get(taskRow.dateKey) - 1;
        mTaskRowCount.put(taskRow.dateKey, numTasks);
        notifyItemRemoved(position);

        if (numTasks == 0) {
            // If that was the last task row in the group, then remove the date as well
            mRows.remove(position - 1);
            mTaskRowCount.removeAt(mTaskRowCount.indexOfKey(taskRow.dateKey));
            notifyItemRemoved(position - 1);
            return position - 1;
        } else {
            return position;
        }
    }

    /**
     * Dismisses history back to the stack view.
     */
    private void dismissHistory() {
        ReferenceCountedTrigger t = new ReferenceCountedTrigger(mContext);
        t.increment();
        EventBus.getDefault().send(new HideHistoryEvent(true /* animate */, t));
        t.decrement();
        EventBus.getDefault().send(new HideHistoryButtonEvent());
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.systemui.recents.history;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.ui.DismissTaskEvent;


/**
 * An item touch handler for items in the history view.
 */
public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCallback {

    private Context mContext;
    private RecentsHistoryAdapter mAdapter;

    public RecentsHistoryItemTouchCallbacks(Context context, RecentsHistoryAdapter adapter) {
        super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
        mContext = context;
        mAdapter = adapter;
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
            RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int viewType = mAdapter.getItemViewType(viewHolder.getAdapterPosition());
        switch (viewType) {
            case RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE:
                // Disallow swiping
                return 0;
            default:
                return super.getSwipeDirs(recyclerView, viewHolder);
        }
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int position = viewHolder.getAdapterPosition();
        if (position != RecyclerView.NO_POSITION) {
            RecentsHistoryAdapter.Row row = mAdapter.getRow(position);
            RecentsHistoryAdapter.TaskRow taskRow = (RecentsHistoryAdapter.TaskRow) row;

            // Remove the task from the system
            EventBus.getDefault().send(new DismissTaskEvent(taskRow.task));
            mAdapter.onTaskRemoved(taskRow.task, position);

            // Keep track of deletions by swiping within history
            MetricsLogger.histogram(mContext, "overview_task_dismissed_source",
                    Constants.Metrics.DismissSourceHistorySwipeGesture);
        }
    }
}
Loading