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

Commit 9c8280da authored by Manu Cornet's avatar Manu Cornet Committed by android-build-merger
Browse files

DO NOT MERGE - 2-dimensional Recents activity.

am: c13df1eb

Change-Id: Idfcea35ba54b69e780bb9159055ea296dd9f14a9
parents fefaccb2 c13df1eb
Loading
Loading
Loading
Loading
+16 −0
Original line number Original line Diff line number Diff line
@@ -267,6 +267,22 @@
            </intent-filter>
            </intent-filter>
        </activity>
        </activity>


        <activity android:name=".recents.grid.RecentsGridActivity"
                  android:label="@string/accessibility_desc_recent_apps"
                  android:exported="false"
                  android:launchMode="singleInstance"
                  android:excludeFromRecents="true"
                  android:stateNotNeeded="true"
                  android:resumeWhilePausing="true"
                  android:screenOrientation="behind"
                  android:resizeableActivity="true"
                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                  android:theme="@style/RecentsTheme.Wallpaper">
            <intent-filter>
                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
            </intent-filter>
        </activity>

        <activity android:name=".recents.tv.RecentsTvActivity"
        <activity android:name=".recents.tv.RecentsTvActivity"
                  android:label="@string/accessibility_desc_recent_apps"
                  android:label="@string/accessibility_desc_recent_apps"
                  android:exported="false"
                  android:exported="false"
+33 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 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"
    android:id="@+id/recents_container">
    <include layout="@layout/recents_stack_action_button" />
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recents_view"
        android:layout_marginLeft="12dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="12dp"
        android:layout_marginBottom="5dp"
        android:gravity="center">
    </FrameLayout>
</LinearLayout>
+4 −0
Original line number Original line Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.systemui.recents.events.component.ShowUserToastEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.grid.RecentsGridImpl;
import com.android.systemui.recents.tv.RecentsTvImpl;
import com.android.systemui.recents.tv.RecentsTvImpl;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.Divider;


@@ -83,6 +84,7 @@ public class Recents extends SystemUI
    static {
    static {
        RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
        RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
        RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY);
        RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY);
        RECENTS_ACTIVITIES.add(RecentsGridImpl.RECENTS_MOSAIC_ACTIVITY);
    }
    }


    // Purely for experimentation
    // Purely for experimentation
@@ -205,6 +207,8 @@ public class Recents extends SystemUI
                getSystemService(Context.UI_MODE_SERVICE);
                getSystemService(Context.UI_MODE_SERVICE);
        if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
        if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
            mImpl = new RecentsTvImpl(mContext);
            mImpl = new RecentsTvImpl(mContext);
        } else if (SystemProperties.getBoolean("ro.recents.grid", false) == true) {
            mImpl = new RecentsGridImpl(mContext);
        } else {
        } else {
            mImpl = new RecentsImpl(mContext);
            mImpl = new RecentsImpl(mContext);
        }
        }
+317 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2016 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.grid;

import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.TaskView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * The main grid recents activity started by the RecentsImpl.
 */
public class RecentsGridActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
    private final static String TAG = "RecentsGridActivity";

    private TaskStack mTaskStack;
    private List<Task> mTasks = new ArrayList<>();
    private List<View> mTaskViews = new ArrayList<>();
    private FrameLayout mRecentsView;
    private TextView mEmptyView;
    private View mClearAllButton;
    private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
    private Rect mDisplayRect = new Rect();
    private LayoutInflater mInflater;
    private boolean mTouchExplorationEnabled;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recents_grid);
        SystemServicesProxy ssp = Recents.getSystemServices();

        mInflater = LayoutInflater.from(this);
        mDisplayOrientation = Utilities.getAppConfiguration(this).orientation;
        mDisplayRect = ssp.getDisplayRect();
        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();

        mRecentsView = (FrameLayout) findViewById(R.id.recents_view);
        LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container);
        mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false);
        mClearAllButton = findViewById(R.id.button);

        FrameLayout.LayoutParams emptyViewLayoutParams = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        emptyViewLayoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
        mEmptyView.setLayoutParams(emptyViewLayoutParams);
        mRecentsView.addView(mEmptyView);

        mClearAllButton.setVisibility(View.VISIBLE);
        LinearLayout.LayoutParams lp =
                (LinearLayout.LayoutParams) mClearAllButton.getLayoutParams();
        lp.gravity = Gravity.END;

        mClearAllButton.setOnClickListener(v -> {
            EventBus.getDefault().send(new DismissAllTaskViewsEvent());
        });

        mRecentsView.setOnClickListener(v -> {
            EventBus.getDefault().send(new HideRecentsEvent(
                    false /* triggeredFromAltTab */, false /* triggeredFromHomeKey */));
        });

        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY);
    }

    private TaskView createView() {
        return (TaskView) mInflater.inflate(R.layout.recents_task_view, mRecentsView, false);
    }

    private void clearTaskViews() {
        for (View taskView : mTaskViews) {
            ViewGroup parent = (ViewGroup) taskView.getParent();
            if (parent != null) {
                parent.removeView(taskView);
            }
        }
        mTaskViews.clear();
    }

    private void updateControlVisibility() {
        boolean empty = (mTasks.size() == 0);
        mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE);
        mEmptyView.setVisibility(empty ? View.VISIBLE : View.INVISIBLE);
        if (empty) {
            mEmptyView.bringToFront();
        }
    }

    private void updateRecentsTasks() {
        RecentsTaskLoader loader = Recents.getTaskLoader();
        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
        if (plan == null) {
            plan = loader.createLoadPlan(this);
        }
        RecentsConfiguration config = Recents.getConfiguration();
        RecentsActivityLaunchState launchState = config.getLaunchState();
        if (!plan.hasTasks()) {
            loader.preloadTasks(plan, -1, !launchState.launchedFromHome);
        }
        int numVisibleTasks = 9;
        mTaskStack = plan.getTaskStack();
        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
        loadOpts.runningTaskId = launchState.launchedToTaskId;
        loadOpts.numVisibleTasks = numVisibleTasks;
        loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
        loader.loadTasks(this, plan, loadOpts);

        List<Task> stackTasks = mTaskStack.getStackTasks();
        Collections.reverse(stackTasks);
        mTasks = stackTasks;

        updateControlVisibility();

        clearTaskViews();
        for (int i = 0; i < mTasks.size(); i++) {
            Task task = mTasks.get(i);
            TaskView taskView = createView();
            taskView.onTaskBound(task, mTouchExplorationEnabled, mDisplayOrientation, mDisplayRect);
            Recents.getTaskLoader().loadTaskData(task);
            taskView.setTouchEnabled(true);
            // Show dismiss button right away.
            taskView.startNoUserInteractionAnimation();
            mTaskViews.add(taskView);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
    }

    @Override
    public void onResume() {
        super.onResume();
        updateRecentsTasks();
    }

    @Override
    protected void onStop() {
        super.onStop();
        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Override
    public void onBackPressed() {
        // Back behaves like the recents button so just trigger a toggle event.
        EventBus.getDefault().send(new ToggleRecentsEvent());
    }

    @Override
    public boolean onPreDraw() {
        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
        int width = mRecentsView.getWidth();
        int height = mRecentsView.getHeight();

        List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
            mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */);
        for (int i = 0; i < rects.size(); i++) {
            Rect rect = rects.get(i);
            View taskView = mTaskViews.get(i);
            taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
            taskView.setTranslationX(rect.left);
            taskView.setTranslationY(rect.top);
            mRecentsView.addView(taskView);
        }
        return true;
    }

    void dismissRecentsToHome() {
        Intent startMain = new Intent(Intent.ACTION_MAIN);
        startMain.addCategory(Intent.CATEGORY_HOME);
        startActivity(startMain);
    }

    /**** EventBus events ****/

    public final void onBusEvent(HideRecentsEvent event) {
        if (event.triggeredFromAltTab) {
            // Do nothing for now.
        } else if (event.triggeredFromHomeKey) {
            dismissRecentsToHome();
        }
    }

    public final void onBusEvent(ToggleRecentsEvent event) {
        // Always go back home for simplicity for now. If recents is entered from another app, this
        // code will eventually need to go back to the original app.
        dismissRecentsToHome();
    }

    public final void onBusEvent(DismissTaskViewEvent event) {
        int taskIndex = mTaskViews.indexOf(event.taskView);
        if (taskIndex != -1) {
            mTasks.remove(taskIndex);
            ((ViewGroup) event.taskView.getParent()).removeView(event.taskView);
            mTaskViews.remove(taskIndex);
            EventBus.getDefault().send(
                    new TaskViewDismissedEvent(event.taskView.getTask(), event.taskView, null));
        }
    }

    public final void onBusEvent(TaskViewDismissedEvent event) {
        mRecentsView.announceForAccessibility(this.getString(
            R.string.accessibility_recents_item_dismissed, event.task.title));
        updateControlVisibility();

        EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));

        MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS,
                event.task.key.getComponent().toString());
    }

    public final void onBusEvent(DeleteTaskDataEvent event) {
        // Remove any stored data from the loader.
        RecentsTaskLoader loader = Recents.getTaskLoader();
        loader.deleteTaskData(event.task, false);

        // Remove the task from activity manager.
        SystemServicesProxy ssp = Recents.getSystemServices();
        ssp.removeTask(event.task.key.id);
    }

    public final void onBusEvent(final DismissAllTaskViewsEvent event) {
        // Keep track of the tasks which will have their data removed.
        ArrayList<Task> tasks = new ArrayList<>(mTaskStack.getStackTasks());
        mRecentsView.announceForAccessibility(this.getString(
                R.string.accessibility_recents_all_items_dismissed));
        mTaskStack.removeAllTasks();
        for (int i = tasks.size() - 1; i >= 0; i--) {
            EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
        }
        mTasks = new ArrayList<>();
        updateRecentsTasks();

        MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS_ALL);
    }

    public final void onBusEvent(AllTaskViewsDismissedEvent event) {
        SystemServicesProxy ssp = Recents.getSystemServices();
        if (!ssp.hasDockedTask()) {
            dismissRecentsToHome();
        }
    }

    public final void onBusEvent(LaunchNextTaskRequestEvent event) {
        // Always go back home for simplicity for now. Quick switch will be supported soon.
        EventBus.getDefault().send(new HideRecentsEvent(false, true));
    }

    public final void onBusEvent(LaunchTaskEvent event) {
        startActivity(event.task.key.baseIntent);
    }
}
+48 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2016 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.grid;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;

import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;

public class RecentsGridImpl extends RecentsImpl {
    public static final String RECENTS_MOSAIC_ACTIVITY =
            "com.android.systemui.recents.grid.RecentsGridActivity";

    public RecentsGridImpl(Context context) {
        super(context);
    }

    @Override
    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
            boolean isHomeStackVisible, boolean animate, int growTarget) {
        Intent intent = new Intent();
        intent.setClassName(RECENTS_PACKAGE, RECENTS_MOSAIC_ACTIVITY);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);

        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
        EventBus.getDefault().send(new RecentsActivityStartingEvent());
    }
}
Loading