Merge "Initial changes to break out AllApps into its own view." into ub-launcher3-burnaby
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#ffffff" />
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
</shape>
|
||||||
@@ -62,6 +62,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<include layout="@layout/apps_view"
|
||||||
|
android:id="@+id/apps_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="invisible" />
|
||||||
</com.android.launcher3.DragLayer>
|
</com.android.launcher3.DragLayer>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
|||||||
@@ -71,6 +71,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<include layout="@layout/apps_view"
|
||||||
|
android:id="@+id/apps_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="invisible" />
|
||||||
</com.android.launcher3.DragLayer>
|
</com.android.launcher3.DragLayer>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<com.android.launcher3.AppsContainerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/apps_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="#22000000"
|
||||||
|
android:descendantFocusability="afterDescendants">
|
||||||
|
<include
|
||||||
|
layout="@layout/apps_list_reveal_view"
|
||||||
|
android:layout_width="420dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
<include
|
||||||
|
layout="@layout/apps_list_view"
|
||||||
|
android:layout_width="420dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
</com.android.launcher3.AppsContainerView>
|
||||||
@@ -71,6 +71,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<include layout="@layout/apps_view"
|
||||||
|
android:id="@+id/apps_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="invisible" />
|
||||||
</com.android.launcher3.DragLayer>
|
</com.android.launcher3.DragLayer>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<com.android.launcher3.BubbleTextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
style="@style/WorkspaceIcon.AppsCustomize"
|
||||||
|
android:id="@+id/application_icon"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="@drawable/focusable_view_bg" />
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/apps_view_row_height"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="@drawable/focusable_view_bg"
|
||||||
|
android:descendantFocusability="afterDescendants">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/section"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:gravity="right"
|
||||||
|
android:textColor="#1ca195"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:focusable="false" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/all_apps_transition_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:elevation="15dp"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:background="@drawable/apps_list_bg"
|
||||||
|
android:focusable="false" />
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<com.android.launcher3.BubbleTextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||||
|
style="@style/WorkspaceIcon.AppsCustomize"
|
||||||
|
android:id="@+id/application_icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="@drawable/focusable_view_bg"
|
||||||
|
launcher:iconPaddingOverride="24dp"
|
||||||
|
launcher:textSizeOverride="16dp"
|
||||||
|
launcher:layoutHorizontal="true" />
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/apps_view_row_height"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="@drawable/focusable_view_bg"
|
||||||
|
android:descendantFocusability="afterDescendants">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/section"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:gravity="left|center_vertical"
|
||||||
|
android:textColor="#009688"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:focusable="false" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<ListView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/apps_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:elevation="15dp"
|
||||||
|
android:background="@drawable/apps_list_bg"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:focusable="true"
|
||||||
|
android:descendantFocusability="afterDescendants" />
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<com.android.launcher3.AppsContainerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/apps_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="#22000000"
|
||||||
|
android:descendantFocusability="afterDescendants">
|
||||||
|
<include
|
||||||
|
layout="@layout/apps_list_reveal_view" />
|
||||||
|
<include
|
||||||
|
layout="@layout/apps_list_view" />
|
||||||
|
</com.android.launcher3.AppsContainerView>
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<dimen name="app_icon_size">64dp</dimen>
|
<dimen name="app_icon_size">64dp</dimen>
|
||||||
|
|
||||||
|
<!-- Apps view -->
|
||||||
|
<dimen name="apps_view_row_height">76dp</dimen>
|
||||||
|
|
||||||
<!-- AppsCustomize -->
|
<!-- AppsCustomize -->
|
||||||
<dimen name="apps_customize_tab_bar_height">60dp</dimen>
|
<dimen name="apps_customize_tab_bar_height">60dp</dimen>
|
||||||
<dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
|
<dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
|
||||||
|
|||||||
@@ -18,6 +18,14 @@
|
|||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
|
<!-- BubbleTextView specific attributes. -->
|
||||||
|
<declare-styleable name="BubbleTextView">
|
||||||
|
<attr name="layoutHorizontal" format="boolean" />
|
||||||
|
<attr name="iconSizeOverride" format="dimension" />
|
||||||
|
<attr name="iconPaddingOverride" format="dimension" />
|
||||||
|
<attr name="textSizeOverride" format="dimension" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
<!-- Page Indicator specific attributes. -->
|
<!-- Page Indicator specific attributes. -->
|
||||||
<declare-styleable name="PageIndicator">
|
<declare-styleable name="PageIndicator">
|
||||||
<attr name="windowSize" format="integer" />
|
<attr name="windowSize" format="integer" />
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
|
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
|
||||||
<dimen name="toolbar_button_horizontal_padding">12dip</dimen>
|
<dimen name="toolbar_button_horizontal_padding">12dip</dimen>
|
||||||
|
|
||||||
|
<!-- Apps view -->
|
||||||
|
<dimen name="apps_view_row_height">64dp</dimen>
|
||||||
|
|
||||||
<!-- AllApps/Customize/AppsCustomize -->
|
<!-- AllApps/Customize/AppsCustomize -->
|
||||||
<!-- The height of the tab bar - if this changes, we should update the
|
<!-- The height of the tab bar - if this changes, we should update the
|
||||||
external icon width/height above to compensate -->
|
external icon width/height above to compensate -->
|
||||||
|
|||||||
@@ -0,0 +1,609 @@
|
|||||||
|
package com.android.launcher3;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.SectionIndexer;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a row in the apps list view.
|
||||||
|
*/
|
||||||
|
class AppsRow {
|
||||||
|
int sectionId;
|
||||||
|
String sectionDescription;
|
||||||
|
List<AppInfo> apps;
|
||||||
|
|
||||||
|
public AppsRow(int sId, String sc, List<AppInfo> ai) {
|
||||||
|
sectionId = sId;
|
||||||
|
sectionDescription = sc;
|
||||||
|
apps = ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppsRow(int sId, List<AppInfo> ai) {
|
||||||
|
sectionId = sId;
|
||||||
|
apps = ai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to an algorithm that generates app rows.
|
||||||
|
*/
|
||||||
|
interface AppRowAlgorithm {
|
||||||
|
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow);
|
||||||
|
public int getIconViewLayoutId();
|
||||||
|
public int getRowViewLayoutId();
|
||||||
|
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the rows in the apps list view.
|
||||||
|
*/
|
||||||
|
class SectionedAppsAlgorithm implements AppRowAlgorithm {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
|
||||||
|
List<AppsRow> rows = new ArrayList<>();
|
||||||
|
LinkedHashMap<String, List<AppInfo>> sections = computeSectionedApps(sortedApps);
|
||||||
|
int sectionId = 0;
|
||||||
|
for (Map.Entry<String, List<AppInfo>> sectionEntry : sections.entrySet()) {
|
||||||
|
String section = sectionEntry.getKey();
|
||||||
|
List<AppInfo> apps = sectionEntry.getValue();
|
||||||
|
int numRows = (int) Math.ceil((float) apps.size() / appsPerRow);
|
||||||
|
for (int i = 0; i < numRows; i++) {
|
||||||
|
List<AppInfo> appsInRow = new ArrayList<>();
|
||||||
|
int offset = i * appsPerRow;
|
||||||
|
for (int j = 0; j < appsPerRow; j++) {
|
||||||
|
if (offset + j < apps.size()) {
|
||||||
|
appsInRow.add(apps.get(offset + j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
rows.add(new AppsRow(sectionId, section, appsInRow));
|
||||||
|
} else {
|
||||||
|
rows.add(new AppsRow(sectionId, appsInRow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sectionId++;
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconViewLayoutId() {
|
||||||
|
return R.layout.apps_grid_row_icon_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowViewLayoutId() {
|
||||||
|
return R.layout.apps_grid_row_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedHashMap<String, List<AppInfo>> computeSectionedApps(List<AppInfo> sortedApps) {
|
||||||
|
LinkedHashMap<String, List<AppInfo>> sections = new LinkedHashMap<>();
|
||||||
|
for (AppInfo info : sortedApps) {
|
||||||
|
String section = getSection(info);
|
||||||
|
List<AppInfo> sectionApps = sections.get(section);
|
||||||
|
if (sectionApps == null) {
|
||||||
|
sectionApps = new ArrayList<>();
|
||||||
|
sections.put(section, sectionApps);
|
||||||
|
}
|
||||||
|
sectionApps.add(info);
|
||||||
|
}
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
|
||||||
|
icon.applyFromApplicationInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSection(AppInfo app) {
|
||||||
|
return app.title.toString().substring(0, 1).toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the rows in the apps grid view.
|
||||||
|
*/
|
||||||
|
class ListedAppsAlgorithm implements AppRowAlgorithm {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
|
||||||
|
List<AppsRow> rows = new ArrayList<>();
|
||||||
|
int sectionId = -1;
|
||||||
|
String prevSection = "";
|
||||||
|
for (AppInfo info : sortedApps) {
|
||||||
|
List<AppInfo> appsInRow = new ArrayList<>();
|
||||||
|
appsInRow.add(info);
|
||||||
|
String section = getSection(info);
|
||||||
|
if (!prevSection.equals(section)) {
|
||||||
|
prevSection = section;
|
||||||
|
sectionId++;
|
||||||
|
rows.add(new AppsRow(sectionId, section, appsInRow));
|
||||||
|
} else {
|
||||||
|
rows.add(new AppsRow(sectionId, appsInRow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconViewLayoutId() {
|
||||||
|
return R.layout.apps_list_row_icon_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowViewLayoutId() {
|
||||||
|
return R.layout.apps_list_row_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
|
||||||
|
icon.applyFromApplicationInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSection(AppInfo app) {
|
||||||
|
return app.title.toString().substring(0, 1).toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The adapter of all the apps
|
||||||
|
*/
|
||||||
|
class AppsListAdapter extends BaseAdapter implements SectionIndexer {
|
||||||
|
|
||||||
|
private LayoutInflater mLayoutInflater;
|
||||||
|
private List<AppsRow> mAppRows = new ArrayList<>();
|
||||||
|
private View.OnTouchListener mTouchListener;
|
||||||
|
private View.OnClickListener mIconClickListener;
|
||||||
|
private View.OnLongClickListener mIconLongClickListener;
|
||||||
|
private AppRowAlgorithm mRowAlgorithm;
|
||||||
|
private int mAppsPerRow;
|
||||||
|
|
||||||
|
public AppsListAdapter(Context context, View.OnTouchListener touchListener,
|
||||||
|
View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
|
||||||
|
mLayoutInflater = LayoutInflater.from(context);
|
||||||
|
mTouchListener = touchListener;
|
||||||
|
mIconClickListener = iconClickListener;
|
||||||
|
mIconLongClickListener = iconLongClickListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setApps(List<AppsRow> apps, int appsPerRow, AppRowAlgorithm algo) {
|
||||||
|
mAppsPerRow = appsPerRow;
|
||||||
|
mRowAlgorithm = algo;
|
||||||
|
mAppRows.clear();
|
||||||
|
mAppRows.addAll(apps);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return mAppRows.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return mAppRows.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
AppsRow info = mAppRows.get(position);
|
||||||
|
ViewGroup row = (ViewGroup) convertView;
|
||||||
|
if (row == null) {
|
||||||
|
// Inflate the row and all the icon children necessary
|
||||||
|
row = (ViewGroup) mLayoutInflater.inflate(mRowAlgorithm.getRowViewLayoutId(),
|
||||||
|
parent, false);
|
||||||
|
for (int i = 0; i < mAppsPerRow; i++) {
|
||||||
|
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
||||||
|
mRowAlgorithm.getIconViewLayoutId(), row, false);
|
||||||
|
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT, 1);
|
||||||
|
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||||
|
icon.setLayoutParams(lp);
|
||||||
|
icon.setOnTouchListener(mTouchListener);
|
||||||
|
icon.setOnClickListener(mIconClickListener);
|
||||||
|
icon.setOnLongClickListener(mIconLongClickListener);
|
||||||
|
icon.setFocusable(true);
|
||||||
|
row.addView(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bind the section header
|
||||||
|
TextView tv = (TextView) row.findViewById(R.id.section);
|
||||||
|
if (info.sectionDescription != null) {
|
||||||
|
tv.setText(info.sectionDescription);
|
||||||
|
tv.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
tv.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
// Bind the icons
|
||||||
|
for (int i = 0; i < mAppsPerRow; i++) {
|
||||||
|
BubbleTextView icon = (BubbleTextView) row.getChildAt(i + 1);
|
||||||
|
if (i < info.apps.size()) {
|
||||||
|
mRowAlgorithm.bindRowViewIconToInfo(icon, info.apps.get(i));
|
||||||
|
icon.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
icon.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getSections() {
|
||||||
|
ArrayList<Object> sections = new ArrayList<>();
|
||||||
|
int prevSectionId = -1;
|
||||||
|
for (AppsRow row : mAppRows) {
|
||||||
|
if (row.sectionId != prevSectionId) {
|
||||||
|
sections.add(row.sectionDescription.toUpperCase());
|
||||||
|
prevSectionId = row.sectionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sections.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPositionForSection(int sectionIndex) {
|
||||||
|
for (int i = 0; i < mAppRows.size(); i++) {
|
||||||
|
AppsRow row = mAppRows.get(i);
|
||||||
|
if (row.sectionId == sectionIndex) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionForPosition(int position) {
|
||||||
|
return mAppRows.get(position).sectionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alphabetically sorted list of applications.
|
||||||
|
*/
|
||||||
|
class AlphabeticalAppList {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callbacks for when this list is modified.
|
||||||
|
*/
|
||||||
|
public interface Callbacks {
|
||||||
|
public void onAppsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AppInfo> mApps;
|
||||||
|
private Callbacks mCb;
|
||||||
|
|
||||||
|
public AlphabeticalAppList(Callbacks cb) {
|
||||||
|
mCb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of applications.
|
||||||
|
*/
|
||||||
|
public List<AppInfo> getApps() {
|
||||||
|
return mApps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current set of apps.
|
||||||
|
*/
|
||||||
|
public void setApps(List<AppInfo> apps) {
|
||||||
|
Collections.sort(apps, LauncherModel.getAppNameComparator());
|
||||||
|
mApps = apps;
|
||||||
|
mCb.onAppsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new apps to the list.
|
||||||
|
*/
|
||||||
|
public void addApps(List<AppInfo> apps) {
|
||||||
|
// We add it in place, in alphabetical order
|
||||||
|
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
|
||||||
|
for (AppInfo info : apps) {
|
||||||
|
// This call will return the exact index of where the item is if >= 0, or the index
|
||||||
|
// where it should be inserted if < 0.
|
||||||
|
int index = Collections.binarySearch(mApps, info, appNameComparator);
|
||||||
|
if (index < 0) {
|
||||||
|
mApps.add(-(index + 1), info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCb.onAppsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates existing apps in the list
|
||||||
|
*/
|
||||||
|
public void updateApps(List<AppInfo> apps) {
|
||||||
|
Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
|
||||||
|
for (AppInfo info : apps) {
|
||||||
|
int index = mApps.indexOf(info);
|
||||||
|
if (index != -1) {
|
||||||
|
mApps.set(index, info);
|
||||||
|
} else {
|
||||||
|
index = Collections.binarySearch(mApps, info, appNameComparator);
|
||||||
|
if (index < 0) {
|
||||||
|
mApps.add(-(index + 1), info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCb.onAppsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes some apps from the list.
|
||||||
|
*/
|
||||||
|
public void removeApps(List<AppInfo> apps) {
|
||||||
|
for (AppInfo info : apps) {
|
||||||
|
int removeIndex = findAppByComponent(mApps, info);
|
||||||
|
if (removeIndex != -1) {
|
||||||
|
mApps.remove(removeIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCb.onAppsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of an app given a target AppInfo.
|
||||||
|
*/
|
||||||
|
private int findAppByComponent(List<AppInfo> apps, AppInfo targetInfo) {
|
||||||
|
ComponentName targetComponent = targetInfo.intent.getComponent();
|
||||||
|
int length = apps.size();
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
AppInfo info = apps.get(i);
|
||||||
|
if (info.user.equals(info.user)
|
||||||
|
&& info.intent.getComponent().equals(targetComponent)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The all apps list view container.
|
||||||
|
*/
|
||||||
|
public class AppsContainerView extends FrameLayout implements DragSource, View.OnTouchListener,
|
||||||
|
View.OnLongClickListener, Insettable, AlphabeticalAppList.Callbacks {
|
||||||
|
|
||||||
|
static final int GRID_LAYOUT = 0;
|
||||||
|
static final int LIST_LAYOUT = 1;
|
||||||
|
static final int USE_LAYOUT = LIST_LAYOUT;
|
||||||
|
|
||||||
|
private Launcher mLauncher;
|
||||||
|
private AppRowAlgorithm mAppRowsAlgorithm;
|
||||||
|
private AppsListAdapter mAdapter;
|
||||||
|
private AlphabeticalAppList mApps;
|
||||||
|
private ListView mList;
|
||||||
|
private int mAppsRowSize;
|
||||||
|
private Point mLastTouchDownPos = new Point();
|
||||||
|
private Rect mPadding = new Rect();
|
||||||
|
|
||||||
|
public AppsContainerView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppsContainerView(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
this(context, attrs, defStyleAttr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
LauncherAppState app = LauncherAppState.getInstance();
|
||||||
|
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||||
|
|
||||||
|
mLauncher = (Launcher) context;
|
||||||
|
if (USE_LAYOUT == GRID_LAYOUT) {
|
||||||
|
mAppRowsAlgorithm = new SectionedAppsAlgorithm();
|
||||||
|
mAppsRowSize = grid.allAppsRowsSize;
|
||||||
|
} else if (USE_LAYOUT == LIST_LAYOUT) {
|
||||||
|
mAppRowsAlgorithm = new ListedAppsAlgorithm();
|
||||||
|
mAppsRowSize = 1;
|
||||||
|
}
|
||||||
|
mAdapter = new AppsListAdapter(context, this, mLauncher, this);
|
||||||
|
mApps = new AlphabeticalAppList(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current set of apps.
|
||||||
|
*/
|
||||||
|
public void setApps(List<AppInfo> apps) {
|
||||||
|
mApps.setApps(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new apps to the list.
|
||||||
|
*/
|
||||||
|
public void addApps(List<AppInfo> apps) {
|
||||||
|
mApps.addApps(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates existing apps in the list
|
||||||
|
*/
|
||||||
|
public void updateApps(List<AppInfo> apps) {
|
||||||
|
mApps.updateApps(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes some apps from the list.
|
||||||
|
*/
|
||||||
|
public void removeApps(List<AppInfo> apps) {
|
||||||
|
mApps.removeApps(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrolls this list view to the top.
|
||||||
|
*/
|
||||||
|
public void scrollToTop() {
|
||||||
|
mList.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content view used for the launcher transitions.
|
||||||
|
*/
|
||||||
|
public View getContentView() {
|
||||||
|
return findViewById(R.id.apps_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reveal view used for the launcher transitions.
|
||||||
|
*/
|
||||||
|
public View getRevealView() {
|
||||||
|
return findViewById(R.id.all_apps_transition_overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppsUpdated() {
|
||||||
|
List<AppsRow> rows = mAppRowsAlgorithm.computeAppRows(mApps.getApps(), mAppsRowSize);
|
||||||
|
mAdapter.setApps(rows, mAppsRowSize, mAppRowsAlgorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
mList = (ListView) findViewById(R.id.apps_list);
|
||||||
|
mList.setFastScrollEnabled(true);
|
||||||
|
mList.setFastScrollAlwaysVisible(true);
|
||||||
|
mList.setItemsCanFocus(true);
|
||||||
|
mList.setAdapter(mAdapter);
|
||||||
|
mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInsets(Rect insets) {
|
||||||
|
setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
|
||||||
|
mPadding.right + insets.right, mPadding.bottom + insets.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_DOWN ||
|
||||||
|
event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||||
|
mLastTouchDownPos.set((int) event.getX(), (int) event.getY());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
// Return early if this is not initiated from a touch
|
||||||
|
if (!v.isInTouchMode()) return false;
|
||||||
|
// When we have exited all apps or are in transition, disregard long clicks
|
||||||
|
if (!mLauncher.isAppsViewVisible() ||
|
||||||
|
mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||||
|
// Return if global dragging is not enabled
|
||||||
|
if (!mLauncher.isDraggingEnabled()) return false;
|
||||||
|
|
||||||
|
// Start the drag
|
||||||
|
mLauncher.getWorkspace().beginDragShared(v, mLastTouchDownPos, this, false);
|
||||||
|
|
||||||
|
// We delay entering spring-loaded mode slightly to make sure the UI
|
||||||
|
// thready is free of any work.
|
||||||
|
postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// We don't enter spring-loaded mode if the drag has been cancelled
|
||||||
|
if (mLauncher.getDragController().isDragging()) {
|
||||||
|
// Go into spring loaded mode (must happen before we startDrag())
|
||||||
|
mLauncher.enterSpringLoadedDragMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFlingToDelete() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppInfoDropTarget() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDeleteDropTarget() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getIntrinsicIconScaleFactor() {
|
||||||
|
LauncherAppState app = LauncherAppState.getInstance();
|
||||||
|
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||||
|
return (float) grid.allAppsIconSizePx / grid.iconSizePx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFlingToDeleteCompleted() {
|
||||||
|
// We just dismiss the drag when we fling, so cleanup here
|
||||||
|
mLauncher.exitSpringLoadedDragModeDelayed(true,
|
||||||
|
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
|
||||||
|
mLauncher.unlockScreenOrientation(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, boolean success) {
|
||||||
|
if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
|
||||||
|
!(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
|
||||||
|
// Exit spring loaded mode if we have not successfully dropped or have not handled the
|
||||||
|
// drop in Workspace
|
||||||
|
mLauncher.exitSpringLoadedDragModeDelayed(true,
|
||||||
|
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
|
||||||
|
}
|
||||||
|
mLauncher.unlockScreenOrientation(false);
|
||||||
|
|
||||||
|
// Display an error message if the drag failed due to there not being enough space on the
|
||||||
|
// target layout we were dropping on.
|
||||||
|
if (!success) {
|
||||||
|
boolean showOutOfSpaceMessage = false;
|
||||||
|
if (target instanceof Workspace) {
|
||||||
|
int currentScreen = mLauncher.getCurrentWorkspaceScreen();
|
||||||
|
Workspace workspace = (Workspace) target;
|
||||||
|
CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
|
||||||
|
ItemInfo itemInfo = (ItemInfo) d.dragInfo;
|
||||||
|
if (layout != null) {
|
||||||
|
layout.calculateSpans(itemInfo);
|
||||||
|
showOutOfSpaceMessage =
|
||||||
|
!layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (showOutOfSpaceMessage) {
|
||||||
|
mLauncher.showOutOfSpaceMessage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.deferDragViewCleanupPostAnimation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -149,10 +149,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
* The different content types that this paged view can show.
|
* The different content types that this paged view can show.
|
||||||
*/
|
*/
|
||||||
public enum ContentType {
|
public enum ContentType {
|
||||||
Applications,
|
|
||||||
Widgets
|
Widgets
|
||||||
}
|
}
|
||||||
private ContentType mContentType = ContentType.Applications;
|
private ContentType mContentType = ContentType.Widgets;
|
||||||
|
|
||||||
// Refs
|
// Refs
|
||||||
private Launcher mLauncher;
|
private Launcher mLauncher;
|
||||||
@@ -164,7 +163,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
private int mSaveInstanceStateItemIndex = -1;
|
private int mSaveInstanceStateItemIndex = -1;
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
private ArrayList<AppInfo> mApps;
|
|
||||||
private ArrayList<Object> mWidgets;
|
private ArrayList<Object> mWidgets;
|
||||||
|
|
||||||
// Caching
|
// Caching
|
||||||
@@ -174,9 +172,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
private int mContentWidth, mContentHeight;
|
private int mContentWidth, mContentHeight;
|
||||||
private int mWidgetCountX, mWidgetCountY;
|
private int mWidgetCountX, mWidgetCountY;
|
||||||
private PagedViewCellLayout mWidgetSpacingLayout;
|
private PagedViewCellLayout mWidgetSpacingLayout;
|
||||||
private int mNumAppsPages;
|
|
||||||
private int mNumWidgetPages;
|
private int mNumWidgetPages;
|
||||||
private Rect mAllAppsPadding = new Rect();
|
|
||||||
|
|
||||||
// Previews & outlines
|
// Previews & outlines
|
||||||
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
|
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
|
||||||
@@ -214,10 +210,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
mLayoutInflater = LayoutInflater.from(context);
|
mLayoutInflater = LayoutInflater.from(context);
|
||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
mApps = new ArrayList<AppInfo>();
|
mWidgets = new ArrayList<>();
|
||||||
mWidgets = new ArrayList<Object>();
|
|
||||||
mIconCache = (LauncherAppState.getInstance()).getIconCache();
|
mIconCache = (LauncherAppState.getInstance()).getIconCache();
|
||||||
mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
|
mRunningTasks = new ArrayList<>();
|
||||||
|
|
||||||
// Save the default widget preview background
|
// Save the default widget preview background
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
|
||||||
@@ -256,10 +251,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
grid.edgeMarginPx, 2 * grid.edgeMarginPx);
|
grid.edgeMarginPx, 2 * grid.edgeMarginPx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAllAppsPadding(Rect r) {
|
|
||||||
mAllAppsPadding.set(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
|
void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
|
||||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
|
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
|
||||||
}
|
}
|
||||||
@@ -277,22 +268,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
int i = -1;
|
int i = -1;
|
||||||
if (getPageCount() > 0) {
|
if (getPageCount() > 0) {
|
||||||
int currentPage = getCurrentPage();
|
int currentPage = getCurrentPage();
|
||||||
if (mContentType == ContentType.Applications) {
|
if (mContentType == ContentType.Widgets) {
|
||||||
AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(currentPage);
|
|
||||||
ShortcutAndWidgetContainer childrenLayout = layout.getShortcutsAndWidgets();
|
|
||||||
int numItemsPerPage = mCellCountX * mCellCountY;
|
|
||||||
int childCount = childrenLayout.getChildCount();
|
|
||||||
if (childCount > 0) {
|
|
||||||
i = (currentPage * numItemsPerPage) + (childCount / 2);
|
|
||||||
}
|
|
||||||
} else if (mContentType == ContentType.Widgets) {
|
|
||||||
int numApps = mApps.size();
|
|
||||||
PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
|
PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
|
||||||
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
||||||
int childCount = layout.getChildCount();
|
int childCount = layout.getChildCount();
|
||||||
if (childCount > 0) {
|
if (childCount > 0) {
|
||||||
i = numApps +
|
i = (currentPage * numItemsPerPage) + (childCount / 2);
|
||||||
(currentPage * numItemsPerPage) + (childCount / 2);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Invalid ContentType");
|
throw new RuntimeException("Invalid ContentType");
|
||||||
@@ -314,13 +295,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
int getPageForComponent(int index) {
|
int getPageForComponent(int index) {
|
||||||
if (index < 0) return 0;
|
if (index < 0) return 0;
|
||||||
|
|
||||||
if (index < mApps.size()) {
|
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
||||||
int numItemsPerPage = mCellCountX * mCellCountY;
|
return index / numItemsPerPage;
|
||||||
return (index / numItemsPerPage);
|
|
||||||
} else {
|
|
||||||
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
|
||||||
return (index - mApps.size()) / numItemsPerPage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Restores the page for an item at the specified index */
|
/** Restores the page for an item at the specified index */
|
||||||
@@ -332,16 +308,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
private void updatePageCounts() {
|
private void updatePageCounts() {
|
||||||
mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
|
mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
|
||||||
(float) (mWidgetCountX * mWidgetCountY));
|
(float) (mWidgetCountX * mWidgetCountY));
|
||||||
mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onDataReady(int width, int height) {
|
protected void onDataReady(int width, int height) {
|
||||||
// Now that the data is ready, we can calculate the content width, the number of cells to
|
|
||||||
// use for each page
|
|
||||||
LauncherAppState app = LauncherAppState.getInstance();
|
|
||||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
|
||||||
mCellCountX = (int) grid.allAppsNumCols;
|
|
||||||
mCellCountY = (int) grid.allAppsNumRows;
|
|
||||||
updatePageCounts();
|
updatePageCounts();
|
||||||
|
|
||||||
// Force a measure to update recalculate the gaps
|
// Force a measure to update recalculate the gaps
|
||||||
@@ -360,7 +329,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
super.onLayout(changed, l, t, r, b);
|
super.onLayout(changed, l, t, r, b);
|
||||||
|
|
||||||
if (!isDataReady()) {
|
if (!isDataReady()) {
|
||||||
if ((!mApps.isEmpty()) && !mWidgets.isEmpty()) {
|
if (!mWidgets.isEmpty()) {
|
||||||
post(new Runnable() {
|
post(new Runnable() {
|
||||||
// This code triggers requestLayout so must be posted outside of the
|
// This code triggers requestLayout so must be posted outside of the
|
||||||
// layout pass.
|
// layout pass.
|
||||||
@@ -438,7 +407,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
// When we have exited all apps or are in transition, disregard clicks
|
// When we have exited all apps or are in transition, disregard clicks
|
||||||
if (!mLauncher.isAllAppsVisible()
|
if (!mLauncher.isWidgetsViewVisible()
|
||||||
|| mLauncher.getWorkspace().isSwitchingState()
|
|| mLauncher.getWorkspace().isSwitchingState()
|
||||||
|| !(v instanceof PagedViewWidget)) return;
|
|| !(v instanceof PagedViewWidget)) return;
|
||||||
|
|
||||||
@@ -456,11 +425,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void determineDraggingStart(android.view.MotionEvent ev) {
|
protected void determineDraggingStart(android.view.MotionEvent ev) {
|
||||||
// Disable dragging by pulling an app down for now.
|
|
||||||
}
|
|
||||||
|
|
||||||
private void beginDraggingApplication(View v) {
|
|
||||||
mLauncher.getWorkspace().beginDragShared(v, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
|
static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
|
||||||
@@ -681,12 +645,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
protected boolean beginDragging(final View v) {
|
protected boolean beginDragging(final View v) {
|
||||||
if (!super.beginDragging(v)) return false;
|
if (!super.beginDragging(v)) return false;
|
||||||
|
|
||||||
if (v instanceof BubbleTextView) {
|
if (v instanceof PagedViewWidget) {
|
||||||
beginDraggingApplication(v);
|
|
||||||
} else if (v instanceof PagedViewWidget) {
|
|
||||||
if (!beginDraggingWidget(v)) {
|
if (!beginDraggingWidget(v)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Unexpected dragging view: " + v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We delay entering spring-loaded mode slightly to make sure the UI
|
// We delay entering spring-loaded mode slightly to make sure the UI
|
||||||
@@ -852,7 +816,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
// Clean up all the async tasks
|
// Clean up all the async tasks
|
||||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
AppsCustomizeAsyncTask task = iter.next();
|
||||||
task.cancel(false);
|
task.cancel(false);
|
||||||
iter.remove();
|
iter.remove();
|
||||||
mDirtyPageContent.set(task.page, true);
|
mDirtyPageContent.set(task.page, true);
|
||||||
@@ -886,7 +850,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
// Update the thread priorities given the direction lookahead
|
// Update the thread priorities given the direction lookahead
|
||||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
AppsCustomizeAsyncTask task = iter.next();
|
||||||
int pageIndex = task.page;
|
int pageIndex = task.page;
|
||||||
if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
|
if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
|
||||||
(mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
|
(mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
|
||||||
@@ -897,36 +861,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Apps PagedView implementation
|
|
||||||
*/
|
|
||||||
private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
|
|
||||||
int childCount = layout.getChildCount();
|
|
||||||
for (int i = 0; i < childCount; ++i) {
|
|
||||||
layout.getChildAt(i).setVisibility(visibility);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void setupPage(AppsCustomizeCellLayout layout) {
|
|
||||||
layout.setGridSize(mCellCountX, mCellCountY);
|
|
||||||
|
|
||||||
// Note: We force a measure here to get around the fact that when we do layout calculations
|
|
||||||
// immediately after syncing, we don't have a proper width. That said, we already know the
|
|
||||||
// expected page width, so we can actually optimize by hiding all the TextView-based
|
|
||||||
// children that are expensive to measure, and let that happen naturally later.
|
|
||||||
setVisibilityOnChildren(layout, View.GONE);
|
|
||||||
int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
|
|
||||||
int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
|
|
||||||
layout.measure(widthSpec, heightSpec);
|
|
||||||
|
|
||||||
Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel);
|
|
||||||
if (bg != null) {
|
|
||||||
bg.setAlpha(mPageBackgroundsVisible ? 255: 0);
|
|
||||||
layout.setBackground(bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisibilityOnChildren(layout, View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPageBackgroundsVisible(boolean visible) {
|
public void setPageBackgroundsVisible(boolean visible) {
|
||||||
mPageBackgroundsVisible = visible;
|
mPageBackgroundsVisible = visible;
|
||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
@@ -938,43 +872,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncAppsPageItems(int page, boolean immediate) {
|
|
||||||
// ensure that we have the right number of items on the pages
|
|
||||||
final boolean isRtl = isLayoutRtl();
|
|
||||||
int numCells = mCellCountX * mCellCountY;
|
|
||||||
int startIndex = page * numCells;
|
|
||||||
int endIndex = Math.min(startIndex + numCells, mApps.size());
|
|
||||||
AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(page);
|
|
||||||
|
|
||||||
layout.removeAllViewsOnPage();
|
|
||||||
ArrayList<Object> items = new ArrayList<Object>();
|
|
||||||
ArrayList<Bitmap> images = new ArrayList<Bitmap>();
|
|
||||||
for (int i = startIndex; i < endIndex; ++i) {
|
|
||||||
AppInfo info = mApps.get(i);
|
|
||||||
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
|
||||||
R.layout.apps_customize_application, layout, false);
|
|
||||||
icon.applyFromApplicationInfo(info);
|
|
||||||
icon.setOnClickListener(mLauncher);
|
|
||||||
icon.setOnLongClickListener(this);
|
|
||||||
icon.setOnTouchListener(this);
|
|
||||||
icon.setOnKeyListener(mKeyListener);
|
|
||||||
icon.setOnFocusChangeListener(layout.mFocusHandlerView);
|
|
||||||
|
|
||||||
int index = i - startIndex;
|
|
||||||
int x = index % mCellCountX;
|
|
||||||
int y = index / mCellCountX;
|
|
||||||
if (isRtl) {
|
|
||||||
x = mCellCountX - x - 1;
|
|
||||||
}
|
|
||||||
layout.addViewToCellLayout(icon, -1, i, new CellLayout.LayoutParams(x,y, 1,1), false);
|
|
||||||
|
|
||||||
items.add(info);
|
|
||||||
images.add(info.iconBitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
enableHwLayersOnVisiblePages();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to return the priority for loading of the specified widget page.
|
* A helper to return the priority for loading of the specified widget page.
|
||||||
*/
|
*/
|
||||||
@@ -991,7 +888,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||||
int minPageDiff = Integer.MAX_VALUE;
|
int minPageDiff = Integer.MAX_VALUE;
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
AppsCustomizeAsyncTask task = iter.next();
|
||||||
minPageDiff = Math.abs(task.page - toPage);
|
minPageDiff = Math.abs(task.page - toPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,7 +923,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
// Prune all tasks that are no longer needed
|
// Prune all tasks that are no longer needed
|
||||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
AppsCustomizeAsyncTask task = iter.next();
|
||||||
int taskPage = task.page;
|
int taskPage = task.page;
|
||||||
if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
|
if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
|
||||||
taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
|
taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
|
||||||
@@ -1264,14 +1161,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
cancelAllTasks();
|
cancelAllTasks();
|
||||||
|
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if (mContentType == ContentType.Applications) {
|
if (mContentType == ContentType.Widgets) {
|
||||||
for (int i = 0; i < mNumAppsPages; ++i) {
|
|
||||||
AppsCustomizeCellLayout layout = new AppsCustomizeCellLayout(context);
|
|
||||||
setupPage(layout);
|
|
||||||
addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
|
|
||||||
LayoutParams.MATCH_PARENT));
|
|
||||||
}
|
|
||||||
} else if (mContentType == ContentType.Widgets) {
|
|
||||||
for (int j = 0; j < mNumWidgetPages; ++j) {
|
for (int j = 0; j < mNumWidgetPages; ++j) {
|
||||||
PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
|
PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
|
||||||
mWidgetCountY);
|
mWidgetCountY);
|
||||||
@@ -1291,7 +1181,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
if (mContentType == ContentType.Widgets) {
|
if (mContentType == ContentType.Widgets) {
|
||||||
syncWidgetPageItems(page, immediate);
|
syncWidgetPageItems(page, immediate);
|
||||||
} else {
|
} else {
|
||||||
syncAppsPageItems(page, immediate);
|
Log.e(TAG, "Unexpected ContentType");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1383,7 +1273,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
|
* We should call thise method whenever the core data changes (mWidgets) so that we can
|
||||||
* appropriately determine when to invalidate the PagedView page data. In cases where the data
|
* appropriately determine when to invalidate the PagedView page data. In cases where the data
|
||||||
* has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
|
* has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
|
||||||
* next onMeasure() pass, which will trigger an invalidatePageData() itself.
|
* next onMeasure() pass, which will trigger an invalidatePageData() itself.
|
||||||
@@ -1399,73 +1289,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApps(ArrayList<AppInfo> list) {
|
|
||||||
mApps = list;
|
|
||||||
Collections.sort(mApps, LauncherModel.getAppNameComparator());
|
|
||||||
updatePageCountsAndInvalidateData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<AppInfo> getApps() {
|
|
||||||
return mApps;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) {
|
|
||||||
// We add it in place, in alphabetical order
|
|
||||||
int count = list.size();
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
AppInfo info = list.get(i);
|
|
||||||
int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator());
|
|
||||||
if (index < 0) {
|
|
||||||
mApps.add(-(index + 1), info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void addApps(ArrayList<AppInfo> list) {
|
|
||||||
addAppsWithoutInvalidate(list);
|
|
||||||
updatePageCountsAndInvalidateData();
|
|
||||||
}
|
|
||||||
private int findAppByComponent(List<AppInfo> list, AppInfo item) {
|
|
||||||
ComponentName removeComponent = item.intent.getComponent();
|
|
||||||
int length = list.size();
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
AppInfo info = list.get(i);
|
|
||||||
if (info.user.equals(item.user)
|
|
||||||
&& info.intent.getComponent().equals(removeComponent)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) {
|
|
||||||
// loop through all the apps and remove apps that have the same component
|
|
||||||
int length = list.size();
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
AppInfo info = list.get(i);
|
|
||||||
int removeIndex = findAppByComponent(mApps, info);
|
|
||||||
if (removeIndex > -1) {
|
|
||||||
mApps.remove(removeIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void removeApps(ArrayList<AppInfo> appInfos) {
|
|
||||||
removeAppsWithoutInvalidate(appInfos);
|
|
||||||
updatePageCountsAndInvalidateData();
|
|
||||||
}
|
|
||||||
public void updateApps(ArrayList<AppInfo> list) {
|
|
||||||
// We remove and re-add the updated applications list because it's properties may have
|
|
||||||
// changed (ie. the title), and this will ensure that the items will be in their proper
|
|
||||||
// place in the list.
|
|
||||||
removeAppsWithoutInvalidate(list);
|
|
||||||
addAppsWithoutInvalidate(list);
|
|
||||||
updatePageCountsAndInvalidateData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
// If we have reset, then we should not continue to restore the previous state
|
// If we have reset, then we should not continue to restore the previous state
|
||||||
mSaveInstanceStateItemIndex = -1;
|
mSaveInstanceStateItemIndex = -1;
|
||||||
|
|
||||||
if (mContentType != ContentType.Applications) {
|
if (mContentType != ContentType.Widgets) {
|
||||||
setContentType(ContentType.Applications);
|
setContentType(ContentType.Widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCurrentPage != 0) {
|
if (mCurrentPage != 0) {
|
||||||
@@ -1479,7 +1308,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
|
|
||||||
public void dumpState() {
|
public void dumpState() {
|
||||||
// TODO: Dump information related to current list of Applications, Widgets, etc.
|
// TODO: Dump information related to current list of Applications, Widgets, etc.
|
||||||
AppInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
|
|
||||||
dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
|
dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1534,10 +1362,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
|||||||
int stringId = R.string.default_scroll_format;
|
int stringId = R.string.default_scroll_format;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (mContentType == ContentType.Applications) {
|
if (mContentType == ContentType.Widgets) {
|
||||||
stringId = R.string.apps_customize_apps_scroll_format;
|
|
||||||
count = mNumAppsPages;
|
|
||||||
} else if (mContentType == ContentType.Widgets) {
|
|
||||||
stringId = R.string.apps_customize_widgets_scroll_format;
|
stringId = R.string.apps_customize_widgets_scroll_format;
|
||||||
count = mNumWidgetPages;
|
count = mNumWidgetPages;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import android.widget.FrameLayout;
|
|||||||
public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
|
public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
|
||||||
static final String LOG_TAG = "AppsCustomizeTabHost";
|
static final String LOG_TAG = "AppsCustomizeTabHost";
|
||||||
|
|
||||||
private static final String APPS_TAB_TAG = "APPS";
|
|
||||||
private static final String WIDGETS_TAB_TAG = "WIDGETS";
|
private static final String WIDGETS_TAB_TAG = "WIDGETS";
|
||||||
|
|
||||||
private AppsCustomizePagedView mPagedView;
|
private AppsCustomizePagedView mPagedView;
|
||||||
@@ -50,10 +49,6 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
|||||||
mPagedView.setContentType(type);
|
mPagedView.setContentType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
|
|
||||||
setContentTypeImmediate(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInsets(Rect insets) {
|
public void setInsets(Rect insets) {
|
||||||
mInsets.set(insets);
|
mInsets.set(insets);
|
||||||
@@ -78,28 +73,39 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
|||||||
return getTabTagForContentType(mPagedView.getContentType());
|
return getTabTagForContentType(mPagedView.getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content view used for the launcher transitions.
|
||||||
|
*/
|
||||||
|
public View getContentView() {
|
||||||
|
return findViewById(R.id.apps_customize_pane_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reveal view used for the launcher transitions.
|
||||||
|
*/
|
||||||
|
public View getRevealView() {
|
||||||
|
return findViewById(R.id.fake_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page indicators view.
|
||||||
|
*/
|
||||||
|
public View getPageIndicators() {
|
||||||
|
return findViewById(R.id.apps_customize_page_indicator);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content type for the specified tab tag.
|
* Returns the content type for the specified tab tag.
|
||||||
*/
|
*/
|
||||||
public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
|
public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
|
||||||
if (tag.equals(APPS_TAB_TAG)) {
|
return AppsCustomizePagedView.ContentType.Widgets;
|
||||||
return AppsCustomizePagedView.ContentType.Applications;
|
|
||||||
} else if (tag.equals(WIDGETS_TAB_TAG)) {
|
|
||||||
return AppsCustomizePagedView.ContentType.Widgets;
|
|
||||||
}
|
|
||||||
return AppsCustomizePagedView.ContentType.Applications;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tab tag for a given content type.
|
* Returns the tab tag for a given content type.
|
||||||
*/
|
*/
|
||||||
public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
|
public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
|
||||||
if (type == AppsCustomizePagedView.ContentType.Applications) {
|
return WIDGETS_TAB_TAG;
|
||||||
return APPS_TAB_TAG;
|
|
||||||
} else if (type == AppsCustomizePagedView.ContentType.Widgets) {
|
|
||||||
return WIDGETS_TAB_TAG;
|
|
||||||
}
|
|
||||||
return APPS_TAB_TAG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,6 +205,7 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
|||||||
ViewGroup parent = (ViewGroup) getParent();
|
ViewGroup parent = (ViewGroup) getParent();
|
||||||
if (parent == null) return;
|
if (parent == null) return;
|
||||||
|
|
||||||
|
View appsView = ((Launcher) getContext()).getAppsView();
|
||||||
View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
|
View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
|
||||||
final int count = parent.getChildCount();
|
final int count = parent.getChildCount();
|
||||||
if (!isChildrenDrawingOrderEnabled()) {
|
if (!isChildrenDrawingOrderEnabled()) {
|
||||||
@@ -207,7 +214,8 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
|||||||
if (child == this) {
|
if (child == this) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (child.getVisibility() == GONE || child == overviewPanel) {
|
if (child.getVisibility() == GONE || child == overviewPanel ||
|
||||||
|
child == appsView) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
child.setVisibility(visibility);
|
child.setVisibility(visibility);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
@@ -49,7 +50,7 @@ public class BubbleTextView extends TextView {
|
|||||||
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
||||||
static final float PADDING_V = 3.0f;
|
static final float PADDING_V = 3.0f;
|
||||||
|
|
||||||
|
private Drawable mIcon;
|
||||||
private final Drawable mBackground;
|
private final Drawable mBackground;
|
||||||
private final CheckLongPressHelper mLongPressHelper;
|
private final CheckLongPressHelper mLongPressHelper;
|
||||||
private final HolographicOutlineHelper mOutlineHelper;
|
private final HolographicOutlineHelper mOutlineHelper;
|
||||||
@@ -62,9 +63,12 @@ public class BubbleTextView extends TextView {
|
|||||||
|
|
||||||
private float mSlop;
|
private float mSlop;
|
||||||
|
|
||||||
private int mTextColor;
|
|
||||||
private final boolean mCustomShadowsEnabled;
|
private final boolean mCustomShadowsEnabled;
|
||||||
private boolean mIsTextVisible;
|
private final boolean mLayoutHorizontal;
|
||||||
|
private final int mIconSize;
|
||||||
|
private final int mIconPaddingSize;
|
||||||
|
private final int mTextSize;
|
||||||
|
private int mTextColor;
|
||||||
|
|
||||||
private boolean mStayPressed;
|
private boolean mStayPressed;
|
||||||
private boolean mIgnorePressedStateChange;
|
private boolean mIgnorePressedStateChange;
|
||||||
@@ -79,10 +83,19 @@ public class BubbleTextView extends TextView {
|
|||||||
|
|
||||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
LauncherAppState app = LauncherAppState.getInstance();
|
||||||
|
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||||
|
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||||
R.styleable.BubbleTextView, defStyle, 0);
|
R.styleable.BubbleTextView, defStyle, 0);
|
||||||
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
|
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
|
||||||
|
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
|
||||||
|
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
|
||||||
|
grid.allAppsIconSizePx);
|
||||||
|
mIconPaddingSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconPaddingOverride,
|
||||||
|
grid.iconDrawablePaddingPx);
|
||||||
|
mTextSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_textSizeOverride,
|
||||||
|
grid.allAppsIconTextSizePx);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
|
|
||||||
if (mCustomShadowsEnabled) {
|
if (mCustomShadowsEnabled) {
|
||||||
@@ -92,6 +105,12 @@ public class BubbleTextView extends TextView {
|
|||||||
} else {
|
} else {
|
||||||
mBackground = null;
|
mBackground = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are laying out horizontal, then center the text vertically
|
||||||
|
if (mLayoutHorizontal) {
|
||||||
|
setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
}
|
||||||
|
|
||||||
mLongPressHelper = new CheckLongPressHelper(this);
|
mLongPressHelper = new CheckLongPressHelper(this);
|
||||||
|
|
||||||
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
|
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
|
||||||
@@ -106,9 +125,7 @@ public class BubbleTextView extends TextView {
|
|||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
|
|
||||||
// Ensure we are using the right text size
|
// Ensure we are using the right text size
|
||||||
LauncherAppState app = LauncherAppState.getInstance();
|
setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
|
||||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
|
||||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
||||||
@@ -119,16 +136,11 @@ public class BubbleTextView extends TextView {
|
|||||||
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
||||||
boolean setDefaultPadding, boolean promiseStateChanged) {
|
boolean setDefaultPadding, boolean promiseStateChanged) {
|
||||||
Bitmap b = info.getIcon(iconCache);
|
Bitmap b = info.getIcon(iconCache);
|
||||||
LauncherAppState app = LauncherAppState.getInstance();
|
|
||||||
|
|
||||||
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
||||||
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
|
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
|
||||||
|
|
||||||
setCompoundDrawables(null, iconDrawable, null, null);
|
setIcon(iconDrawable, mIconSize, setDefaultPadding ? mIconPaddingSize : -1);
|
||||||
if (setDefaultPadding) {
|
|
||||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
|
||||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
|
||||||
}
|
|
||||||
if (info.contentDescription != null) {
|
if (info.contentDescription != null) {
|
||||||
setContentDescription(info.contentDescription);
|
setContentDescription(info.contentDescription);
|
||||||
}
|
}
|
||||||
@@ -141,13 +153,7 @@ public class BubbleTextView extends TextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void applyFromApplicationInfo(AppInfo info) {
|
public void applyFromApplicationInfo(AppInfo info) {
|
||||||
LauncherAppState app = LauncherAppState.getInstance();
|
setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize, mIconPaddingSize);
|
||||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
|
||||||
|
|
||||||
Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
|
|
||||||
topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
|
|
||||||
setCompoundDrawables(null, topDrawable, null, null);
|
|
||||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
|
||||||
setText(info.title);
|
setText(info.title);
|
||||||
if (info.contentDescription != null) {
|
if (info.contentDescription != null) {
|
||||||
setContentDescription(info.contentDescription);
|
setContentDescription(info.contentDescription);
|
||||||
@@ -155,7 +161,6 @@ public class BubbleTextView extends TextView {
|
|||||||
setTag(info);
|
setTag(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean setFrame(int left, int top, int right, int bottom) {
|
protected boolean setFrame(int left, int top, int right, int bottom) {
|
||||||
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
|
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
|
||||||
@@ -186,10 +191,19 @@ public class BubbleTextView extends TextView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the icon for this view. */
|
||||||
|
public Drawable getIcon() {
|
||||||
|
return mIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether the layout is horizontal. */
|
||||||
|
public boolean isLayoutHorizontal() {
|
||||||
|
return mLayoutHorizontal;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateIconState() {
|
private void updateIconState() {
|
||||||
Drawable top = getCompoundDrawables()[1];
|
if (mIcon instanceof FastBitmapDrawable) {
|
||||||
if (top instanceof FastBitmapDrawable) {
|
((FastBitmapDrawable) mIcon).setPressed(isPressed() || mStayPressed);
|
||||||
((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,10 +339,9 @@ public class BubbleTextView extends TextView {
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
|
|
||||||
if (mBackground != null) mBackground.setCallback(this);
|
if (mBackground != null) mBackground.setCallback(this);
|
||||||
Drawable top = getCompoundDrawables()[1];
|
|
||||||
|
|
||||||
if (top instanceof PreloadIconDrawable) {
|
if (mIcon instanceof PreloadIconDrawable) {
|
||||||
((PreloadIconDrawable) top).applyPreloaderTheme(getPreloaderTheme());
|
((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme());
|
||||||
}
|
}
|
||||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||||
}
|
}
|
||||||
@@ -358,11 +371,6 @@ public class BubbleTextView extends TextView {
|
|||||||
} else {
|
} else {
|
||||||
super.setTextColor(res.getColor(android.R.color.transparent));
|
super.setTextColor(res.getColor(android.R.color.transparent));
|
||||||
}
|
}
|
||||||
mIsTextVisible = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTextVisible() {
|
|
||||||
return mIsTextVisible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -385,15 +393,13 @@ public class BubbleTextView extends TextView {
|
|||||||
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
|
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
|
||||||
info.getInstallProgress() : 0)) : 100;
|
info.getInstallProgress() : 0)) : 100;
|
||||||
|
|
||||||
Drawable[] drawables = getCompoundDrawables();
|
if (mIcon != null) {
|
||||||
Drawable top = drawables[1];
|
|
||||||
if (top != null) {
|
|
||||||
final PreloadIconDrawable preloadDrawable;
|
final PreloadIconDrawable preloadDrawable;
|
||||||
if (top instanceof PreloadIconDrawable) {
|
if (mIcon instanceof PreloadIconDrawable) {
|
||||||
preloadDrawable = (PreloadIconDrawable) top;
|
preloadDrawable = (PreloadIconDrawable) mIcon;
|
||||||
} else {
|
} else {
|
||||||
preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
|
preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
|
||||||
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
|
setIcon(preloadDrawable, mIconSize, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
preloadDrawable.setLevel(progressLevel);
|
preloadDrawable.setLevel(progressLevel);
|
||||||
@@ -417,4 +423,23 @@ public class BubbleTextView extends TextView {
|
|||||||
}
|
}
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the icon for this view based on the layout direction.
|
||||||
|
*/
|
||||||
|
private Drawable setIcon(Drawable icon, int iconSize, int drawablePadding) {
|
||||||
|
mIcon = icon;
|
||||||
|
if (iconSize != -1) {
|
||||||
|
mIcon.setBounds(0, 0, iconSize, iconSize);
|
||||||
|
}
|
||||||
|
if (mLayoutHorizontal) {
|
||||||
|
setCompoundDrawablesRelative(mIcon, null, null, null);
|
||||||
|
} else {
|
||||||
|
setCompoundDrawablesRelative(null, mIcon, null, null);
|
||||||
|
}
|
||||||
|
if (drawablePadding != -1) {
|
||||||
|
setCompoundDrawablePadding(drawablePadding);
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ public class DeviceProfile {
|
|||||||
int hotseatAllAppsRank;
|
int hotseatAllAppsRank;
|
||||||
int allAppsNumRows;
|
int allAppsNumRows;
|
||||||
int allAppsNumCols;
|
int allAppsNumCols;
|
||||||
|
// TODO(winsonc): to be used with the grid layout
|
||||||
|
int allAppsRowsSize;
|
||||||
int searchBarSpaceWidthPx;
|
int searchBarSpaceWidthPx;
|
||||||
int searchBarSpaceHeightPx;
|
int searchBarSpaceHeightPx;
|
||||||
int pageIndicatorHeightPx;
|
int pageIndicatorHeightPx;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Point;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -47,7 +48,6 @@ import android.view.inputmethod.EditorInfo;
|
|||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.launcher3.FolderInfo.FolderListener;
|
import com.android.launcher3.FolderInfo.FolderListener;
|
||||||
import com.android.launcher3.Workspace.ItemOperator;
|
import com.android.launcher3.Workspace.ItemOperator;
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLauncher.getWorkspace().beginDragShared(v, this);
|
mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
|
||||||
|
|
||||||
mCurrentDragInfo = item;
|
mCurrentDragInfo = item;
|
||||||
mEmptyCellRank = item.rank;
|
mEmptyCellRank = item.rank;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3308,7 +3308,7 @@ public class LauncherModel extends BroadcastReceiver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of ResolveInfos/AppWindowInfos in sorted order
|
// Returns a list of ResolveInfos/AppWidgetInfos in sorted order
|
||||||
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
|
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
|
||||||
PackageManager packageManager = context.getPackageManager();
|
PackageManager packageManager = context.getPackageManager();
|
||||||
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
|
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
|
||||||
|
|||||||
@@ -0,0 +1,832 @@
|
|||||||
|
/*
|
||||||
|
* 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.launcher3;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.PropertyValuesHolder;
|
||||||
|
import android.animation.TimeInterpolator;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewAnimationUtils;
|
||||||
|
import android.view.animation.AccelerateInterpolator;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: figure out what kind of tests we can write for this
|
||||||
|
*
|
||||||
|
* Things to test when changing the following class.
|
||||||
|
* - Home from workspace
|
||||||
|
* - from center screen
|
||||||
|
* - from other screens
|
||||||
|
* - Home from all apps
|
||||||
|
* - from center screen
|
||||||
|
* - from other screens
|
||||||
|
* - Back from all apps
|
||||||
|
* - from center screen
|
||||||
|
* - from other screens
|
||||||
|
* - Launch app from workspace and quit
|
||||||
|
* - with back
|
||||||
|
* - with home
|
||||||
|
* - Launch app from all apps and quit
|
||||||
|
* - with back
|
||||||
|
* - with home
|
||||||
|
* - Go to a screen that's not the default, then all
|
||||||
|
* apps, and launch and app, and go back
|
||||||
|
* - with back
|
||||||
|
* -with home
|
||||||
|
* - On workspace, long press power and go back
|
||||||
|
* - with back
|
||||||
|
* - with home
|
||||||
|
* - On all apps, long press power and go back
|
||||||
|
* - with back
|
||||||
|
* - with home
|
||||||
|
* - On workspace, power off
|
||||||
|
* - On all apps, power off
|
||||||
|
* - Launch an app and turn off the screen while in that app
|
||||||
|
* - Go back with home key
|
||||||
|
* - Go back with back key TODO: make this not go to workspace
|
||||||
|
* - From all apps
|
||||||
|
* - From workspace
|
||||||
|
* - Enter and exit car mode (becuase it causes an extra configuration changed)
|
||||||
|
* - From all apps
|
||||||
|
* - From the center workspace
|
||||||
|
* - From another workspace
|
||||||
|
*/
|
||||||
|
public class LauncherStateTransitionAnimation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callbacks made during the state transition
|
||||||
|
*/
|
||||||
|
interface Callbacks {
|
||||||
|
public void onStateTransitionHideSearchBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private callbacks made during transition setup.
|
||||||
|
*/
|
||||||
|
static abstract class PrivateTransitionCallbacks {
|
||||||
|
void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {}
|
||||||
|
void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {}
|
||||||
|
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
float getMaterialRevealViewStartFinalRadius() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(View revealView,
|
||||||
|
View allAppsButtonView) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String TAG = "LauncherStateTransitionAnimation";
|
||||||
|
|
||||||
|
// Flags to determine how to set the layers on views before the transition animation
|
||||||
|
public static final int BUILD_LAYER = 0;
|
||||||
|
public static final int BUILD_AND_SET_LAYER = 1;
|
||||||
|
public static final int SINGLE_FRAME_DELAY = 16;
|
||||||
|
|
||||||
|
private Launcher mLauncher;
|
||||||
|
private Callbacks mCb;
|
||||||
|
private AnimatorSet mStateAnimation;
|
||||||
|
|
||||||
|
public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
|
||||||
|
mLauncher = l;
|
||||||
|
mCb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an animation to the apps view.
|
||||||
|
*/
|
||||||
|
public void startAnimationToAllApps(final boolean animated) {
|
||||||
|
final AppsContainerView toView = mLauncher.getAppsView();
|
||||||
|
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||||
|
private int[] mAllAppsToPanelDelta;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRevealViewVisible(View revealView, View contentView,
|
||||||
|
View allAppsButtonView) {
|
||||||
|
toView.setBackground(null);
|
||||||
|
// Get the y delta between the center of the page and the center of the all apps
|
||||||
|
// button
|
||||||
|
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
|
||||||
|
allAppsButtonView, null);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||||
|
return mAllAppsToPanelDelta[0];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||||
|
return mAllAppsToPanelDelta[1];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewStartFinalRadius() {
|
||||||
|
int allAppsButtonSize = LauncherAppState.getInstance().
|
||||||
|
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
|
||||||
|
return allAppsButtonSize / 2;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||||
|
final View revealView, final View allAppsButtonView) {
|
||||||
|
return new AnimatorListenerAdapter() {
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
allAppsButtonView.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
allAppsButtonView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
|
||||||
|
toView.getRevealView(), null, animated, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an animation to the widgets view.
|
||||||
|
*/
|
||||||
|
public void startAnimationToWidgets(final boolean animated) {
|
||||||
|
final AppsCustomizeTabHost toView = mLauncher.getWidgetsView();
|
||||||
|
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||||
|
@Override
|
||||||
|
public void onRevealViewVisible(View revealView, View contentView,
|
||||||
|
View allAppsButtonView) {
|
||||||
|
// Hide the real page background, and swap in the fake one
|
||||||
|
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false);
|
||||||
|
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
|
||||||
|
// Show the real page background
|
||||||
|
((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||||
|
return 0.3f;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||||
|
return revealView.getMeasuredHeight() / 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
|
||||||
|
toView.getRevealView(), toView.getPageIndicators(), animated, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts and animation to the workspace from the current overlay view.
|
||||||
|
*/
|
||||||
|
public void startAnimationToWorkspace(final Launcher.State fromState,
|
||||||
|
final Workspace.State toWorkspaceState, final boolean animated,
|
||||||
|
final Runnable onCompleteRunnable) {
|
||||||
|
if (toWorkspaceState != Workspace.State.NORMAL &&
|
||||||
|
toWorkspaceState != Workspace.State.SPRING_LOADED &&
|
||||||
|
toWorkspaceState != Workspace.State.OVERVIEW) {
|
||||||
|
Log.e(TAG, "Unexpected call to startAnimationToWorkspace");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
|
||||||
|
startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, animated,
|
||||||
|
onCompleteRunnable);
|
||||||
|
} else {
|
||||||
|
startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, animated,
|
||||||
|
onCompleteRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and starts a new animation to a particular overlay view.
|
||||||
|
*/
|
||||||
|
private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
|
||||||
|
final View contentView, final View revealView, final View pageIndicatorsView,
|
||||||
|
final boolean animated, final PrivateTransitionCallbacks pCb) {
|
||||||
|
final Resources res = mLauncher.getResources();
|
||||||
|
final boolean material = Utilities.isLmpOrAbove();
|
||||||
|
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
|
||||||
|
final int itemsAlphaStagger =
|
||||||
|
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||||
|
|
||||||
|
final View allAppsButtonView = mLauncher.getAllAppsButton();
|
||||||
|
final View fromView = mLauncher.getWorkspace();
|
||||||
|
|
||||||
|
final HashMap<View, Integer> layerViews = new HashMap<>();
|
||||||
|
|
||||||
|
// If for some reason our views aren't initialized, don't animate
|
||||||
|
boolean initialized = allAppsButtonView != null;
|
||||||
|
|
||||||
|
// Cancel the current animation
|
||||||
|
cancelAnimation();
|
||||||
|
|
||||||
|
// Create the workspace animation.
|
||||||
|
// NOTE: this call apparently also sets the state for the workspace if !animated
|
||||||
|
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
|
||||||
|
toWorkspaceState, animated, layerViews);
|
||||||
|
|
||||||
|
if (animated && initialized) {
|
||||||
|
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
|
||||||
|
|
||||||
|
// Setup the reveal view animation
|
||||||
|
int width = revealView.getMeasuredWidth();
|
||||||
|
int height = revealView.getMeasuredHeight();
|
||||||
|
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
|
||||||
|
revealView.setVisibility(View.VISIBLE);
|
||||||
|
revealView.setAlpha(0f);
|
||||||
|
revealView.setTranslationY(0f);
|
||||||
|
revealView.setTranslationX(0f);
|
||||||
|
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
|
||||||
|
|
||||||
|
// Calculate the final animation values
|
||||||
|
final float revealViewToAlpha;
|
||||||
|
final float revealViewToXDrift;
|
||||||
|
final float revealViewToYDrift;
|
||||||
|
if (material) {
|
||||||
|
revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||||
|
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
|
||||||
|
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
|
||||||
|
} else {
|
||||||
|
revealViewToAlpha = 0f;
|
||||||
|
revealViewToYDrift = 2 * height / 3;
|
||||||
|
revealViewToXDrift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the animators
|
||||||
|
PropertyValuesHolder panelAlpha =
|
||||||
|
PropertyValuesHolder.ofFloat("alpha", revealViewToAlpha, 1f);
|
||||||
|
PropertyValuesHolder panelDriftY =
|
||||||
|
PropertyValuesHolder.ofFloat("translationY", revealViewToYDrift, 0);
|
||||||
|
PropertyValuesHolder panelDriftX =
|
||||||
|
PropertyValuesHolder.ofFloat("translationX", revealViewToXDrift, 0);
|
||||||
|
ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
|
||||||
|
panelAlpha, panelDriftY, panelDriftX);
|
||||||
|
panelAlphaAndDrift.setDuration(revealDuration);
|
||||||
|
panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||||
|
|
||||||
|
// Play the animation
|
||||||
|
layerViews.put(revealView, BUILD_AND_SET_LAYER);
|
||||||
|
mStateAnimation.play(panelAlphaAndDrift);
|
||||||
|
|
||||||
|
// Setup the animation for the page indicators
|
||||||
|
if (pageIndicatorsView != null) {
|
||||||
|
pageIndicatorsView.setAlpha(0.01f);
|
||||||
|
ObjectAnimator indicatorsAlpha =
|
||||||
|
ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
|
||||||
|
indicatorsAlpha.setDuration(revealDuration);
|
||||||
|
mStateAnimation.play(indicatorsAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the animation for the content view
|
||||||
|
contentView.setVisibility(View.VISIBLE);
|
||||||
|
contentView.setAlpha(0f);
|
||||||
|
contentView.setTranslationY(revealViewToYDrift);
|
||||||
|
layerViews.put(contentView, BUILD_AND_SET_LAYER);
|
||||||
|
|
||||||
|
// Create the individual animators
|
||||||
|
ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
|
||||||
|
revealViewToYDrift, 0);
|
||||||
|
pageDrift.setDuration(revealDuration);
|
||||||
|
pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||||
|
pageDrift.setStartDelay(itemsAlphaStagger);
|
||||||
|
mStateAnimation.play(pageDrift);
|
||||||
|
|
||||||
|
ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f);
|
||||||
|
itemsAlpha.setDuration(revealDuration);
|
||||||
|
itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
|
||||||
|
itemsAlpha.setStartDelay(itemsAlphaStagger);
|
||||||
|
mStateAnimation.play(itemsAlpha);
|
||||||
|
|
||||||
|
if (material) {
|
||||||
|
// Animate the all apps button
|
||||||
|
float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
|
||||||
|
AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
|
||||||
|
revealView, allAppsButtonView);
|
||||||
|
Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
|
||||||
|
height / 2, startRadius, revealRadius);
|
||||||
|
reveal.setDuration(revealDuration);
|
||||||
|
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||||
|
if (listener != null) {
|
||||||
|
reveal.addListener(listener);
|
||||||
|
}
|
||||||
|
mStateAnimation.play(reveal);
|
||||||
|
}
|
||||||
|
|
||||||
|
mStateAnimation.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
dispatchOnLauncherTransitionEnd(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionEnd(toView, animated, false);
|
||||||
|
|
||||||
|
// Hide the reveal view
|
||||||
|
revealView.setVisibility(View.INVISIBLE);
|
||||||
|
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
|
||||||
|
|
||||||
|
// Disable all necessary layers
|
||||||
|
for (View v : layerViews.keySet()) {
|
||||||
|
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the search bar
|
||||||
|
mCb.onStateTransitionHideSearchBar();
|
||||||
|
|
||||||
|
// This can hold unnecessary references to views.
|
||||||
|
mStateAnimation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Play the workspace animation
|
||||||
|
if (workspaceAnim != null) {
|
||||||
|
mStateAnimation.play(workspaceAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch the prepare transition signal
|
||||||
|
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionPrepare(toView, animated, false);
|
||||||
|
|
||||||
|
|
||||||
|
final AnimatorSet stateAnimation = mStateAnimation;
|
||||||
|
final Runnable startAnimRunnable = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
// Check that mStateAnimation hasn't changed while
|
||||||
|
// we waited for a layout/draw pass
|
||||||
|
if (mStateAnimation != stateAnimation)
|
||||||
|
return;
|
||||||
|
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||||
|
|
||||||
|
// Enable all necessary layers
|
||||||
|
for (View v : layerViews.keySet()) {
|
||||||
|
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||||
|
}
|
||||||
|
if (Utilities.isViewAttachedToWindow(v)) {
|
||||||
|
v.buildLayer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus the new view
|
||||||
|
toView.requestFocus();
|
||||||
|
|
||||||
|
mStateAnimation.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toView.bringToFront();
|
||||||
|
toView.setVisibility(View.VISIBLE);
|
||||||
|
toView.post(startAnimRunnable);
|
||||||
|
} else {
|
||||||
|
toView.setTranslationX(0.0f);
|
||||||
|
toView.setTranslationY(0.0f);
|
||||||
|
toView.setScaleX(1.0f);
|
||||||
|
toView.setScaleY(1.0f);
|
||||||
|
toView.setVisibility(View.VISIBLE);
|
||||||
|
toView.bringToFront();
|
||||||
|
|
||||||
|
// Show the content view
|
||||||
|
contentView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// Hide the search bar
|
||||||
|
mCb.onStateTransitionHideSearchBar();
|
||||||
|
|
||||||
|
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionEnd(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionPrepare(toView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionEnd(toView, animated, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts and animation to the workspace from the apps view.
|
||||||
|
*/
|
||||||
|
private void startAnimationToWorkspaceFromAllApps(final Launcher.State fromState,
|
||||||
|
final Workspace.State toWorkspaceState, final boolean animated,
|
||||||
|
final Runnable onCompleteRunnable) {
|
||||||
|
AppsContainerView appsView = mLauncher.getAppsView();
|
||||||
|
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||||
|
int[] mAllAppsToPanelDelta;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRevealViewVisible(View revealView, View contentView,
|
||||||
|
View allAppsButtonView) {
|
||||||
|
// Get the y delta between the center of the page and the center of the all apps
|
||||||
|
// button
|
||||||
|
mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
|
||||||
|
allAppsButtonView, null);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalXDrift(View revealView) {
|
||||||
|
return mAllAppsToPanelDelta[0];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||||
|
return mAllAppsToPanelDelta[1];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||||
|
// No alpha anim from all apps
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
float getMaterialRevealViewStartFinalRadius() {
|
||||||
|
int allAppsButtonSize = LauncherAppState.getInstance().
|
||||||
|
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
|
||||||
|
return allAppsButtonSize / 2;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||||
|
final View revealView, final View allAppsButtonView) {
|
||||||
|
return new AnimatorListenerAdapter() {
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
// We set the alpha instead of visibility to ensure that the focus does not
|
||||||
|
// get taken from the all apps view
|
||||||
|
allAppsButtonView.setVisibility(View.VISIBLE);
|
||||||
|
allAppsButtonView.setAlpha(0f);
|
||||||
|
}
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
// Hide the reveal view
|
||||||
|
revealView.setVisibility(View.INVISIBLE);
|
||||||
|
|
||||||
|
// Show the all apps button, and focus it
|
||||||
|
allAppsButtonView.setAlpha(1f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
|
||||||
|
appsView.getRevealView(), null /* pageIndicatorsView */, animated,
|
||||||
|
onCompleteRunnable, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts and animation to the workspace from the widgets view.
|
||||||
|
*/
|
||||||
|
private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
|
||||||
|
final Workspace.State toWorkspaceState, final boolean animated,
|
||||||
|
final Runnable onCompleteRunnable) {
|
||||||
|
AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView();
|
||||||
|
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
|
||||||
|
@Override
|
||||||
|
public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {
|
||||||
|
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
|
||||||
|
|
||||||
|
// Hide the real page background, and swap in the fake one
|
||||||
|
pagedView.stopScrolling();
|
||||||
|
pagedView.setPageBackgroundsVisible(false);
|
||||||
|
revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
|
||||||
|
|
||||||
|
// Hide the side pages of the Widget tray to avoid some ugly edge cases
|
||||||
|
final View currentPage = pagedView.getPageAt(pagedView.getNextPage());
|
||||||
|
int count = pagedView.getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View child = pagedView.getChildAt(i);
|
||||||
|
if (child != currentPage) {
|
||||||
|
child.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
|
||||||
|
AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
|
||||||
|
|
||||||
|
// Show the real page background and force-update the page
|
||||||
|
pagedView.setPageBackgroundsVisible(true);
|
||||||
|
pagedView.setCurrentPage(pagedView.getNextPage());
|
||||||
|
pagedView.updateCurrentPageScroll();
|
||||||
|
|
||||||
|
// Unhide the side pages
|
||||||
|
int count = pagedView.getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
View child = pagedView.getChildAt(i);
|
||||||
|
child.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public float getMaterialRevealViewFinalYDrift(View revealView) {
|
||||||
|
return revealView.getMeasuredHeight() / 2;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
float getMaterialRevealViewFinalAlpha(View revealView) {
|
||||||
|
return 0.4f;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
|
||||||
|
final View revealView, final View allAppsButtonView) {
|
||||||
|
return new AnimatorListenerAdapter() {
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
// Hide the reveal view
|
||||||
|
revealView.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
|
||||||
|
widgetsView.getContentView(), widgetsView.getRevealView(),
|
||||||
|
widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and starts a new animation to the workspace.
|
||||||
|
*/
|
||||||
|
private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
|
||||||
|
final View fromView, final View contentView, final View revealView,
|
||||||
|
final View pageIndicatorsView, final boolean animated,
|
||||||
|
final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
|
||||||
|
final Resources res = mLauncher.getResources();
|
||||||
|
final boolean material = Utilities.isLmpOrAbove();
|
||||||
|
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
|
||||||
|
final int itemsAlphaStagger =
|
||||||
|
res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
|
||||||
|
|
||||||
|
final View allAppsButtonView = mLauncher.getAllAppsButton();
|
||||||
|
final View toView = mLauncher.getWorkspace();
|
||||||
|
|
||||||
|
final HashMap<View, Integer> layerViews = new HashMap<>();
|
||||||
|
|
||||||
|
// If for some reason our views aren't initialized, don't animate
|
||||||
|
boolean initialized = allAppsButtonView != null;
|
||||||
|
|
||||||
|
// Cancel the current animation
|
||||||
|
cancelAnimation();
|
||||||
|
|
||||||
|
// Create the workspace animation.
|
||||||
|
// NOTE: this call apparently also sets the state for the workspace if !animated
|
||||||
|
Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
|
||||||
|
toWorkspaceState, animated, layerViews);
|
||||||
|
|
||||||
|
if (animated && initialized) {
|
||||||
|
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
|
||||||
|
|
||||||
|
// Play the workspace animation
|
||||||
|
if (workspaceAnim != null) {
|
||||||
|
mStateAnimation.play(workspaceAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hideAppsCustomizeHelper is called in some cases when it is already hidden
|
||||||
|
// don't perform all these no-op animations. In particularly, this was causing
|
||||||
|
// the all-apps button to pop in and out.
|
||||||
|
if (fromView.getVisibility() == View.VISIBLE) {
|
||||||
|
int width = revealView.getMeasuredWidth();
|
||||||
|
int height = revealView.getMeasuredHeight();
|
||||||
|
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
|
||||||
|
revealView.setVisibility(View.VISIBLE);
|
||||||
|
revealView.setAlpha(1f);
|
||||||
|
revealView.setTranslationY(0);
|
||||||
|
layerViews.put(revealView, BUILD_AND_SET_LAYER);
|
||||||
|
pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
|
||||||
|
|
||||||
|
// Calculate the final animation values
|
||||||
|
final float revealViewToXDrift;
|
||||||
|
final float revealViewToYDrift;
|
||||||
|
if (material) {
|
||||||
|
revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
|
||||||
|
revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
|
||||||
|
} else {
|
||||||
|
revealViewToYDrift = 2 * height / 3;
|
||||||
|
revealViewToXDrift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The vertical motion of the apps panel should be delayed by one frame
|
||||||
|
// from the conceal animation in order to give the right feel. We correspondingly
|
||||||
|
// shorten the duration so that the slide and conceal end at the same time.
|
||||||
|
TimeInterpolator decelerateInterpolator = material ?
|
||||||
|
new LogDecelerateInterpolator(100, 0) :
|
||||||
|
new DecelerateInterpolator(1f);
|
||||||
|
ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
|
||||||
|
0, revealViewToYDrift);
|
||||||
|
panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||||
|
panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||||
|
panelDriftY.setInterpolator(decelerateInterpolator);
|
||||||
|
mStateAnimation.play(panelDriftY);
|
||||||
|
|
||||||
|
ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
|
||||||
|
0, revealViewToXDrift);
|
||||||
|
panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||||
|
panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||||
|
panelDriftX.setInterpolator(decelerateInterpolator);
|
||||||
|
mStateAnimation.play(panelDriftX);
|
||||||
|
|
||||||
|
// Setup animation for the reveal panel alpha
|
||||||
|
final float revealViewToAlpha = !material ? 0f :
|
||||||
|
pCb.getMaterialRevealViewFinalAlpha(revealView);
|
||||||
|
if (revealViewToAlpha != 1f) {
|
||||||
|
ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
|
||||||
|
1f, revealViewToAlpha);
|
||||||
|
panelAlpha.setDuration(material ? revealDuration : 150);
|
||||||
|
panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||||
|
panelAlpha.setInterpolator(decelerateInterpolator);
|
||||||
|
mStateAnimation.play(panelAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the animation for the content view
|
||||||
|
layerViews.put(contentView, BUILD_AND_SET_LAYER);
|
||||||
|
|
||||||
|
// Create the individual animators
|
||||||
|
ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(contentView, "translationY",
|
||||||
|
0, revealViewToYDrift);
|
||||||
|
contentView.setTranslationY(0);
|
||||||
|
pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
|
||||||
|
pageDrift.setInterpolator(decelerateInterpolator);
|
||||||
|
pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
|
||||||
|
mStateAnimation.play(pageDrift);
|
||||||
|
|
||||||
|
contentView.setAlpha(1f);
|
||||||
|
ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(contentView, "alpha", 1f, 0f);
|
||||||
|
itemsAlpha.setDuration(100);
|
||||||
|
itemsAlpha.setInterpolator(decelerateInterpolator);
|
||||||
|
mStateAnimation.play(itemsAlpha);
|
||||||
|
|
||||||
|
// Setup the page indicators animation
|
||||||
|
if (pageIndicatorsView != null) {
|
||||||
|
pageIndicatorsView.setAlpha(1f);
|
||||||
|
ObjectAnimator indicatorsAlpha =
|
||||||
|
LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
|
||||||
|
indicatorsAlpha.setDuration(revealDuration);
|
||||||
|
indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||||
|
mStateAnimation.play(indicatorsAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (material) {
|
||||||
|
// Animate the all apps button
|
||||||
|
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
|
||||||
|
AnimatorListenerAdapter listener =
|
||||||
|
pCb.getMaterialRevealViewAnimatorListener(revealView, allAppsButtonView);
|
||||||
|
Animator reveal =
|
||||||
|
LauncherAnimUtils.createCircularReveal(revealView, width / 2,
|
||||||
|
height / 2, revealRadius, finalRadius);
|
||||||
|
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
|
||||||
|
reveal.setDuration(revealDuration);
|
||||||
|
reveal.setStartDelay(itemsAlphaStagger);
|
||||||
|
if (listener != null) {
|
||||||
|
reveal.addListener(listener);
|
||||||
|
}
|
||||||
|
mStateAnimation.play(reveal);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionPrepare(toView, animated, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mStateAnimation.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
fromView.setVisibility(View.GONE);
|
||||||
|
dispatchOnLauncherTransitionEnd(fromView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionEnd(toView, animated, true);
|
||||||
|
|
||||||
|
// Run any queued runnables
|
||||||
|
if (onCompleteRunnable != null) {
|
||||||
|
onCompleteRunnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animation complete callback
|
||||||
|
pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
|
||||||
|
|
||||||
|
// Disable all necessary layers
|
||||||
|
for (View v : layerViews.keySet()) {
|
||||||
|
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset page transforms
|
||||||
|
if (contentView != null) {
|
||||||
|
contentView.setTranslationX(0);
|
||||||
|
contentView.setTranslationY(0);
|
||||||
|
contentView.setAlpha(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can hold unnecessary references to views.
|
||||||
|
mStateAnimation = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final AnimatorSet stateAnimation = mStateAnimation;
|
||||||
|
final Runnable startAnimRunnable = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
// Check that mStateAnimation hasn't changed while
|
||||||
|
// we waited for a layout/draw pass
|
||||||
|
if (mStateAnimation != stateAnimation)
|
||||||
|
return;
|
||||||
|
dispatchOnLauncherTransitionStart(fromView, animated, false);
|
||||||
|
dispatchOnLauncherTransitionStart(toView, animated, false);
|
||||||
|
|
||||||
|
// Enable all necessary layers
|
||||||
|
for (View v : layerViews.keySet()) {
|
||||||
|
if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
|
||||||
|
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||||
|
}
|
||||||
|
if (Utilities.isLmpOrAbove()) {
|
||||||
|
v.buildLayer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mStateAnimation.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fromView.post(startAnimRunnable);
|
||||||
|
} else {
|
||||||
|
fromView.setVisibility(View.GONE);
|
||||||
|
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionStart(fromView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionEnd(fromView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionPrepare(toView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionStart(toView, animated, true);
|
||||||
|
dispatchOnLauncherTransitionEnd(toView, animated, true);
|
||||||
|
|
||||||
|
// Run any queued runnables
|
||||||
|
if (onCompleteRunnable != null) {
|
||||||
|
onCompleteRunnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches the prepare-transition event to suitable views.
|
||||||
|
*/
|
||||||
|
void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
|
||||||
|
if (v instanceof LauncherTransitionable) {
|
||||||
|
((LauncherTransitionable) v).onLauncherTransitionPrepare(mLauncher, animated,
|
||||||
|
toWorkspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches the start-transition event to suitable views.
|
||||||
|
*/
|
||||||
|
void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
|
||||||
|
if (v instanceof LauncherTransitionable) {
|
||||||
|
((LauncherTransitionable) v).onLauncherTransitionStart(mLauncher, animated,
|
||||||
|
toWorkspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the workspace transition step as well
|
||||||
|
dispatchOnLauncherTransitionStep(v, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches the step-transition event to suitable views.
|
||||||
|
*/
|
||||||
|
void dispatchOnLauncherTransitionStep(View v, float t) {
|
||||||
|
if (v instanceof LauncherTransitionable) {
|
||||||
|
((LauncherTransitionable) v).onLauncherTransitionStep(mLauncher, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches the end-transition event to suitable views.
|
||||||
|
*/
|
||||||
|
void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
|
||||||
|
if (v instanceof LauncherTransitionable) {
|
||||||
|
((LauncherTransitionable) v).onLauncherTransitionEnd(mLauncher, animated,
|
||||||
|
toWorkspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the workspace transition step as well
|
||||||
|
dispatchOnLauncherTransitionStep(v, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current animation.
|
||||||
|
*/
|
||||||
|
private void cancelAnimation() {
|
||||||
|
if (mStateAnimation != null) {
|
||||||
|
mStateAnimation.setDuration(0);
|
||||||
|
mStateAnimation.cancel();
|
||||||
|
mStateAnimation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -109,7 +109,7 @@ public abstract class PagedViewWithDraggableItems extends PagedView
|
|||||||
// Return early if we are still animating the pages
|
// Return early if we are still animating the pages
|
||||||
if (mNextPage != INVALID_PAGE) return false;
|
if (mNextPage != INVALID_PAGE) return false;
|
||||||
// When we have exited all apps or are in transition, disregard long clicks
|
// When we have exited all apps or are in transition, disregard long clicks
|
||||||
if (!mLauncher.isAllAppsVisible() ||
|
if (!mLauncher.isWidgetsViewVisible() ||
|
||||||
mLauncher.getWorkspace().isSwitchingState()) return false;
|
mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||||
// Return if global dragging is not enabled
|
// Return if global dragging is not enabled
|
||||||
if (!mLauncher.isDraggingEnabled()) return false;
|
if (!mLauncher.isDraggingEnabled()) return false;
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ public class WidgetPreviewLoader {
|
|||||||
private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
|
private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
|
||||||
private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
|
private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
|
||||||
|
|
||||||
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
|
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
|
||||||
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
|
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>();
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final int mAppIconSize;
|
private final int mAppIconSize;
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.android.launcher3;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
class SectionedWidgetsRow {
|
||||||
|
String section;
|
||||||
|
List<List<Object>> widgets;
|
||||||
|
|
||||||
|
public SectionedWidgetsRow(String sc) {
|
||||||
|
section = sc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SectionedWidgetsAlgorithm {
|
||||||
|
public List<SectionedWidgetsRow> computeSectionedWidgetRows(List<Object> sortedWidgets,
|
||||||
|
int widgetsPerRow) {
|
||||||
|
List<SectionedWidgetsRow> rows = new ArrayList<>();
|
||||||
|
LinkedHashMap<String, List<Object>> sections = computeSectionedApps(sortedWidgets);
|
||||||
|
for (Map.Entry<String, List<Object>> sectionEntry : sections.entrySet()) {
|
||||||
|
String section = sectionEntry.getKey();
|
||||||
|
SectionedWidgetsRow row = new SectionedWidgetsRow(section);
|
||||||
|
List<Object> widgets = sectionEntry.getValue();
|
||||||
|
int numRows = (int) Math.ceil((float) widgets.size() / widgetsPerRow);
|
||||||
|
for (int i = 0; i < numRows; i++) {
|
||||||
|
List<Object> widgetsInRow = new ArrayList<>();
|
||||||
|
int offset = i * widgetsPerRow;
|
||||||
|
for (int j = 0; j < widgetsPerRow; j++) {
|
||||||
|
widgetsInRow.add(widgets.get(offset + j));
|
||||||
|
}
|
||||||
|
row.widgets.add(widgetsInRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedHashMap<String, List<Object>> computeSectionedApps(List<Object> sortedWidgets) {
|
||||||
|
LinkedHashMap<String, List<Object>> sections = new LinkedHashMap<>();
|
||||||
|
for (Object info : sortedWidgets) {
|
||||||
|
String section = getSection(info);
|
||||||
|
List<Object> sectionedWidgets = sections.get(section);
|
||||||
|
if (sectionedWidgets == null) {
|
||||||
|
sectionedWidgets = new ArrayList<>();
|
||||||
|
sections.put(section, sectionedWidgets);
|
||||||
|
}
|
||||||
|
sectionedWidgets.add(info);
|
||||||
|
}
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSection(Object widgetOrShortcut) {
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The widgets list view container.
|
||||||
|
*/
|
||||||
|
public class WidgetsContainerView extends FrameLayout {
|
||||||
|
|
||||||
|
|
||||||
|
public WidgetsContainerView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetsContainerView(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
this(context, attrs, defStyleAttr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1528,7 +1528,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
@Override
|
@Override
|
||||||
public void announceForAccessibility(CharSequence text) {
|
public void announceForAccessibility(CharSequence text) {
|
||||||
// Don't announce if apps is on top of us.
|
// Don't announce if apps is on top of us.
|
||||||
if (!mLauncher.isAllAppsVisible()) {
|
if (!mLauncher.isAppsViewVisible()) {
|
||||||
super.announceForAccessibility(text);
|
super.announceForAccessibility(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1816,7 +1816,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
|
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
|
||||||
if (!mLauncher.isAllAppsVisible()) {
|
if (!mLauncher.isAppsViewVisible()) {
|
||||||
final Folder openFolder = getOpenFolder();
|
final Folder openFolder = getOpenFolder();
|
||||||
if (openFolder != null) {
|
if (openFolder != null) {
|
||||||
return openFolder.requestFocus(direction, previouslyFocusedRect);
|
return openFolder.requestFocus(direction, previouslyFocusedRect);
|
||||||
@@ -1837,7 +1837,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
|
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
|
||||||
if (!mLauncher.isAllAppsVisible()) {
|
if (!mLauncher.isAppsViewVisible()) {
|
||||||
final Folder openFolder = getOpenFolder();
|
final Folder openFolder = getOpenFolder();
|
||||||
if (openFolder != null) {
|
if (openFolder != null) {
|
||||||
openFolder.addFocusables(views, direction);
|
openFolder.addFocusables(views, direction);
|
||||||
@@ -2046,8 +2046,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
// If this is a text view, use its drawable instead
|
// If this is a text view, use its drawable instead
|
||||||
if (v instanceof TextView) {
|
if (v instanceof TextView) {
|
||||||
TextView tv = (TextView) v;
|
Drawable d = getTextViewIcon((TextView) v);
|
||||||
Drawable d = tv.getCompoundDrawables()[1];
|
|
||||||
Rect bounds = getDrawableBounds(d);
|
Rect bounds = getDrawableBounds(d);
|
||||||
bmpWidth = bounds.width();
|
bmpWidth = bounds.width();
|
||||||
bmpHeight = bounds.height();
|
bmpHeight = bounds.height();
|
||||||
@@ -2348,7 +2347,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
|
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
|
||||||
} else {
|
} else {
|
||||||
if (layerViews != null) {
|
if (layerViews != null) {
|
||||||
layerViews.put(cl, Launcher.BUILD_LAYER);
|
layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
|
||||||
}
|
}
|
||||||
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
|
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
|
||||||
LauncherViewPropertyAnimator alphaAnim =
|
LauncherViewPropertyAnimator alphaAnim =
|
||||||
@@ -2400,8 +2399,8 @@ public class Workspace extends SmoothPagedView
|
|||||||
if (layerViews != null) {
|
if (layerViews != null) {
|
||||||
// If layerViews is not null, we add these views, and indicate that
|
// If layerViews is not null, we add these views, and indicate that
|
||||||
// the caller can manage layer state.
|
// the caller can manage layer state.
|
||||||
layerViews.put(hotseat, Launcher.BUILD_AND_SET_LAYER);
|
layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||||
layerViews.put(overviewPanel, Launcher.BUILD_AND_SET_LAYER);
|
layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise let the animator handle layer management.
|
// Otherwise let the animator handle layer management.
|
||||||
hotseatAlpha.withLayer();
|
hotseatAlpha.withLayer();
|
||||||
@@ -2430,7 +2429,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
if (layerViews != null) {
|
if (layerViews != null) {
|
||||||
// If layerViews is not null, we add these views, and indicate that
|
// If layerViews is not null, we add these views, and indicate that
|
||||||
// the caller can manage layer state.
|
// the caller can manage layer state.
|
||||||
layerViews.put(searchBar, Launcher.BUILD_AND_SET_LAYER);
|
layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise let the animator handle layer management.
|
// Otherwise let the animator handle layer management.
|
||||||
searchBarAlpha.withLayer();
|
searchBarAlpha.withLayer();
|
||||||
@@ -2583,6 +2582,19 @@ public class Workspace extends SmoothPagedView
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the drawable for the given text view.
|
||||||
|
*/
|
||||||
|
public static Drawable getTextViewIcon(TextView tv) {
|
||||||
|
final Drawable[] drawables = tv.getCompoundDrawables();
|
||||||
|
for (int i = 0; i < drawables.length; i++) {
|
||||||
|
if (drawables[i] != null) {
|
||||||
|
return drawables[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the View v into the given Canvas.
|
* Draw the View v into the given Canvas.
|
||||||
*
|
*
|
||||||
@@ -2598,7 +2610,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
destCanvas.save();
|
destCanvas.save();
|
||||||
if (v instanceof TextView) {
|
if (v instanceof TextView) {
|
||||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
Drawable d = getTextViewIcon((TextView) v);
|
||||||
Rect bounds = getDrawableBounds(d);
|
Rect bounds = getDrawableBounds(d);
|
||||||
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
|
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
|
||||||
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
|
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
|
||||||
@@ -2635,7 +2647,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
|
|
||||||
int padding = expectedPadding.get();
|
int padding = expectedPadding.get();
|
||||||
if (v instanceof TextView) {
|
if (v instanceof TextView) {
|
||||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
Drawable d = getTextViewIcon((TextView) v);
|
||||||
Rect bounds = getDrawableBounds(d);
|
Rect bounds = getDrawableBounds(d);
|
||||||
b = Bitmap.createBitmap(bounds.width() + padding,
|
b = Bitmap.createBitmap(bounds.width() + padding,
|
||||||
bounds.height() + padding, Bitmap.Config.ARGB_8888);
|
bounds.height() + padding, Bitmap.Config.ARGB_8888);
|
||||||
@@ -2716,11 +2728,12 @@ public class Workspace extends SmoothPagedView
|
|||||||
beginDragShared(child, this, accessible);
|
beginDragShared(child, this, accessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginDragShared(View child, DragSource source) {
|
public void beginDragShared(View child, DragSource source, boolean accessible) {
|
||||||
beginDragShared(child, source, false);
|
beginDragShared(child, new Point(), source, accessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginDragShared(View child, DragSource source, boolean accessible) {
|
public void beginDragShared(View child, Point relativeTouchPos, DragSource source,
|
||||||
|
boolean accessible) {
|
||||||
child.clearFocus();
|
child.clearFocus();
|
||||||
child.setPressed(false);
|
child.setPressed(false);
|
||||||
|
|
||||||
@@ -2745,11 +2758,23 @@ public class Workspace extends SmoothPagedView
|
|||||||
Point dragVisualizeOffset = null;
|
Point dragVisualizeOffset = null;
|
||||||
Rect dragRect = null;
|
Rect dragRect = null;
|
||||||
if (child instanceof BubbleTextView) {
|
if (child instanceof BubbleTextView) {
|
||||||
|
BubbleTextView icon = (BubbleTextView) child;
|
||||||
int iconSize = grid.iconSizePx;
|
int iconSize = grid.iconSizePx;
|
||||||
int top = child.getPaddingTop();
|
int top = child.getPaddingTop();
|
||||||
int left = (bmpWidth - iconSize) / 2;
|
int left = (bmpWidth - iconSize) / 2;
|
||||||
int right = left + iconSize;
|
int right = left + iconSize;
|
||||||
int bottom = top + iconSize;
|
int bottom = top + iconSize;
|
||||||
|
if (icon.isLayoutHorizontal()) {
|
||||||
|
// If the layout is horizontal, then if we are just picking up the icon, then just
|
||||||
|
// use the child position since the icon is top-left aligned. Otherwise, offset
|
||||||
|
// the drag layer position horizontally so that the icon is under the current
|
||||||
|
// touch position.
|
||||||
|
if (icon.getIcon().getBounds().contains(relativeTouchPos.x, relativeTouchPos.y)) {
|
||||||
|
dragLayerX = Math.round(mTempXY[0]);
|
||||||
|
} else {
|
||||||
|
dragLayerX = Math.round(mTempXY[0] + relativeTouchPos.x - (bmpWidth / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
dragLayerY += top;
|
dragLayerY += top;
|
||||||
// Note: The drag region is used to calculate drag layer offsets, but the
|
// Note: The drag region is used to calculate drag layer offsets, but the
|
||||||
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
|
||||||
@@ -2831,18 +2856,6 @@ public class Workspace extends SmoothPagedView
|
|||||||
tmpB.recycle();
|
tmpB.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,
|
|
||||||
int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
|
|
||||||
View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
|
|
||||||
|
|
||||||
final int[] cellXY = new int[2];
|
|
||||||
target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
|
|
||||||
addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
|
|
||||||
|
|
||||||
LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],
|
|
||||||
cellXY[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean transitionStateShouldAllowDrop() {
|
public boolean transitionStateShouldAllowDrop() {
|
||||||
return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
|
return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
|
||||||
(mState == State.NORMAL || mState == State.SPRING_LOADED));
|
(mState == State.NORMAL || mState == State.SPRING_LOADED));
|
||||||
@@ -4769,7 +4782,7 @@ public class Workspace extends SmoothPagedView
|
|||||||
updates.contains(info)) {
|
updates.contains(info)) {
|
||||||
ShortcutInfo si = (ShortcutInfo) info;
|
ShortcutInfo si = (ShortcutInfo) info;
|
||||||
BubbleTextView shortcut = (BubbleTextView) v;
|
BubbleTextView shortcut = (BubbleTextView) v;
|
||||||
boolean oldPromiseState = shortcut.getCompoundDrawables()[1]
|
boolean oldPromiseState = getTextViewIcon(shortcut)
|
||||||
instanceof PreloadIconDrawable;
|
instanceof PreloadIconDrawable;
|
||||||
shortcut.applyFromShortcutInfo(si, mIconCache, true,
|
shortcut.applyFromShortcutInfo(si, mIconCache, true,
|
||||||
si.isPromise() != oldPromiseState);
|
si.isPromise() != oldPromiseState);
|
||||||
|
|||||||
Reference in New Issue
Block a user