1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.recents;
18
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.app.FragmentManager;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.graphics.Rect;
26import android.os.Bundle;
27import android.util.Pair;
28import android.view.LayoutInflater;
29import android.view.View;
30import android.widget.Button;
31import com.android.systemui.R;
32import com.android.systemui.recents.misc.SystemServicesProxy;
33import com.android.systemui.recents.model.RecentsTaskLoader;
34import com.android.systemui.recents.model.Task;
35import com.android.systemui.recents.RecentsActivity;
36import com.android.systemui.recents.views.RecentsView;
37
38import java.util.ArrayList;
39
40/**
41 * A helper for the dialogs that show when task debugging is on.
42 */
43public class RecentsResizeTaskDialog extends DialogFragment {
44
45    static final String TAG = "RecentsResizeTaskDialog";
46
47    // The various window arrangements we can handle.
48    private static final int PLACE_LEFT = 1;
49    private static final int PLACE_RIGHT = 2;
50    private static final int PLACE_TOP = 3;
51    private static final int PLACE_BOTTOM = 4;
52    private static final int PLACE_TOP_LEFT = 5;
53    private static final int PLACE_TOP_RIGHT = 6;
54    private static final int PLACE_BOTTOM_LEFT = 7;
55    private static final int PLACE_BOTTOM_RIGHT = 8;
56    private static final int PLACE_FULL = 9;
57
58    // The button resource ID combined with the arrangement command.
59    private static final int[][] BUTTON_DEFINITIONS =
60           {{R.id.place_left, PLACE_LEFT},
61            {R.id.place_right, PLACE_RIGHT},
62            {R.id.place_top, PLACE_TOP},
63            {R.id.place_bottom, PLACE_BOTTOM},
64            {R.id.place_top_left, PLACE_TOP_LEFT},
65            {R.id.place_top_right, PLACE_TOP_RIGHT},
66            {R.id.place_bottom_left, PLACE_BOTTOM_LEFT},
67            {R.id.place_bottom_right, PLACE_BOTTOM_RIGHT},
68            {R.id.place_full, PLACE_FULL}};
69
70    // The task we want to resize.
71    private FragmentManager mFragmentManager;
72    private View mResizeTaskDialogContent;
73    private RecentsActivity mRecentsActivity;
74    private RecentsView mRecentsView;
75    private SystemServicesProxy mSsp;
76    private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
77    private Task[] mTasks = {null, null, null, null};
78
79    public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
80        mFragmentManager = mgr;
81        mRecentsActivity = activity;
82        mSsp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
83    }
84
85    /** Shows the resize-task dialog. */
86    void showResizeTaskDialog(Task mainTask, RecentsView rv) {
87        mTasks[0] = mainTask;
88        mRecentsView = rv;
89
90        show(mFragmentManager, TAG);
91    }
92
93    /** Creates a new resize-task dialog. */
94    private void createResizeTaskDialog(final Context context, LayoutInflater inflater,
95            AlertDialog.Builder builder) {
96        builder.setTitle(R.string.recents_caption_resize);
97        mResizeTaskDialogContent =
98                inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
99
100        for (int i = 0; i < BUTTON_DEFINITIONS.length; i++) {
101            Button b = (Button)mResizeTaskDialogContent.findViewById(BUTTON_DEFINITIONS[i][0]);
102            if (b != null) {
103                final int action = BUTTON_DEFINITIONS[i][1];
104                b.setOnClickListener(
105                        new View.OnClickListener() {
106                            public void onClick(View v) {
107                                placeTasks(action);
108                            }
109                        });
110            }
111        }
112
113        builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
114            @Override
115            public void onClick(DialogInterface dialog, int which) {
116                dismiss();
117            }
118        });
119
120        builder.setView(mResizeTaskDialogContent);
121    }
122
123    /** Helper function to place window(s) on the display according to an arrangement request. */
124    private void placeTasks(int arrangement) {
125        Rect rect = mSsp.getWindowRect();
126        for (int i = 0; i < mBounds.length; ++i) {
127            mBounds[i].set(rect);
128            if (i != 0) {
129                mTasks[i] = null;
130            }
131        }
132        int additionalTasks = 0;
133        switch (arrangement) {
134            case PLACE_LEFT:
135                mBounds[0].right = mBounds[0].centerX();
136                mBounds[1].left = mBounds[0].right;
137                additionalTasks = 1;
138                break;
139            case PLACE_RIGHT:
140                mBounds[1].right = mBounds[1].centerX();
141                mBounds[0].left = mBounds[1].right;
142                additionalTasks = 1;
143                break;
144            case PLACE_TOP:
145                mBounds[0].bottom = mBounds[0].centerY();
146                mBounds[1].top = mBounds[0].bottom;
147                additionalTasks = 1;
148                break;
149            case PLACE_BOTTOM:
150                mBounds[1].bottom = mBounds[1].centerY();
151                mBounds[0].top = mBounds[1].bottom;
152                additionalTasks = 1;
153                break;
154            case PLACE_TOP_LEFT:  // TL, TR, BL, BR
155                mBounds[0].right = mBounds[0].centerX();
156                mBounds[0].bottom = mBounds[0].centerY();
157                mBounds[1].left = mBounds[0].right;
158                mBounds[1].bottom = mBounds[0].bottom;
159                mBounds[2].right = mBounds[0].right;
160                mBounds[2].top = mBounds[0].bottom;
161                mBounds[3].left = mBounds[0].right;
162                mBounds[3].top = mBounds[0].bottom;
163                additionalTasks = 3;
164                break;
165            case PLACE_TOP_RIGHT:  // TR, TL, BR, BL
166                mBounds[0].left = mBounds[0].centerX();
167                mBounds[0].bottom = mBounds[0].centerY();
168                mBounds[1].right = mBounds[0].left;
169                mBounds[1].bottom = mBounds[0].bottom;
170                mBounds[2].left = mBounds[0].left;
171                mBounds[2].top = mBounds[0].bottom;
172                mBounds[3].right = mBounds[0].left;
173                mBounds[3].top = mBounds[0].bottom;
174                additionalTasks = 3;
175                break;
176            case PLACE_BOTTOM_LEFT:  // BL, BR, TL, TR
177                mBounds[0].right = mBounds[0].centerX();
178                mBounds[0].top = mBounds[0].centerY();
179                mBounds[1].left = mBounds[0].right;
180                mBounds[1].top = mBounds[0].top;
181                mBounds[2].right = mBounds[0].right;
182                mBounds[2].bottom = mBounds[0].top;
183                mBounds[3].left = mBounds[0].right;
184                mBounds[3].bottom = mBounds[0].top;
185                additionalTasks = 3;
186                break;
187            case PLACE_BOTTOM_RIGHT:  // BR, BL, TR, TL
188                mBounds[0].left = mBounds[0].centerX();
189                mBounds[0].top = mBounds[0].centerY();
190                mBounds[1].right = mBounds[0].left;
191                mBounds[1].top = mBounds[0].top;
192                mBounds[2].left = mBounds[0].left;
193                mBounds[2].bottom = mBounds[0].top;
194                mBounds[3].right = mBounds[0].left;
195                mBounds[3].bottom = mBounds[0].top;
196                additionalTasks = 3;
197                break;
198            case PLACE_FULL:
199                // Nothing to change.
200                break;
201        }
202
203        // Get the other tasks.
204        for (int i = 1; i <= additionalTasks && mTasks[i - 1] != null; ++i) {
205            mTasks[i] = mRecentsView.getNextTaskOrTopTask(mTasks[i - 1]);
206            // Do stop if we circled back to the first item.
207            if (mTasks[i] == mTasks[0]) {
208                mTasks[i] = null;
209            }
210        }
211
212        // Get rid of the dialog.
213        dismiss();
214        mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
215
216        // Resize all tasks beginning from the "oldest" one.
217        for (int i = additionalTasks; i >= 0; --i) {
218            if (mTasks[i] != null) {
219               mSsp.resizeTask(mTasks[i].key.id, mBounds[i]);
220            }
221        }
222
223        // Show tasks as they might not be currently visible - beginning with the oldest so that
224        // the focus ends on the selected one.
225        for (int i = additionalTasks; i >= 0; --i) {
226            if (mTasks[i] != null) {
227                mRecentsView.launchTask(mTasks[i]);
228            }
229        }
230    }
231
232    @Override
233    public Dialog onCreateDialog(Bundle args) {
234        final Context context = this.getActivity();
235        LayoutInflater inflater = getActivity().getLayoutInflater();
236        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
237        createResizeTaskDialog(context, inflater, builder);
238        return builder.create();
239    }
240}
241