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_height="match_parent"
|
||||
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>
|
||||
|
||||
<ViewStub
|
||||
|
||||
@@ -71,6 +71,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
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>
|
||||
|
||||
<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_height="match_parent"
|
||||
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>
|
||||
|
||||
<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>
|
||||
<dimen name="app_icon_size">64dp</dimen>
|
||||
|
||||
<!-- Apps view -->
|
||||
<dimen name="apps_view_row_height">76dp</dimen>
|
||||
|
||||
<!-- AppsCustomize -->
|
||||
<dimen name="apps_customize_tab_bar_height">60dp</dimen>
|
||||
<dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
|
||||
<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. -->
|
||||
<declare-styleable name="PageIndicator">
|
||||
<attr name="windowSize" format="integer" />
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
|
||||
<dimen name="toolbar_button_horizontal_padding">12dip</dimen>
|
||||
|
||||
<!-- Apps view -->
|
||||
<dimen name="apps_view_row_height">64dp</dimen>
|
||||
|
||||
<!-- AllApps/Customize/AppsCustomize -->
|
||||
<!-- The height of the tab bar - if this changes, we should update the
|
||||
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.
|
||||
*/
|
||||
public enum ContentType {
|
||||
Applications,
|
||||
Widgets
|
||||
}
|
||||
private ContentType mContentType = ContentType.Applications;
|
||||
private ContentType mContentType = ContentType.Widgets;
|
||||
|
||||
// Refs
|
||||
private Launcher mLauncher;
|
||||
@@ -164,7 +163,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
private int mSaveInstanceStateItemIndex = -1;
|
||||
|
||||
// Content
|
||||
private ArrayList<AppInfo> mApps;
|
||||
private ArrayList<Object> mWidgets;
|
||||
|
||||
// Caching
|
||||
@@ -174,9 +172,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
private int mContentWidth, mContentHeight;
|
||||
private int mWidgetCountX, mWidgetCountY;
|
||||
private PagedViewCellLayout mWidgetSpacingLayout;
|
||||
private int mNumAppsPages;
|
||||
private int mNumWidgetPages;
|
||||
private Rect mAllAppsPadding = new Rect();
|
||||
|
||||
// Previews & outlines
|
||||
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
|
||||
@@ -214,10 +210,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
super(context, attrs);
|
||||
mLayoutInflater = LayoutInflater.from(context);
|
||||
mPackageManager = context.getPackageManager();
|
||||
mApps = new ArrayList<AppInfo>();
|
||||
mWidgets = new ArrayList<Object>();
|
||||
mWidgets = new ArrayList<>();
|
||||
mIconCache = (LauncherAppState.getInstance()).getIconCache();
|
||||
mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
|
||||
mRunningTasks = new ArrayList<>();
|
||||
|
||||
// Save the default widget preview background
|
||||
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);
|
||||
}
|
||||
|
||||
void setAllAppsPadding(Rect r) {
|
||||
mAllAppsPadding.set(r);
|
||||
}
|
||||
|
||||
void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
|
||||
}
|
||||
@@ -277,22 +268,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
int i = -1;
|
||||
if (getPageCount() > 0) {
|
||||
int currentPage = getCurrentPage();
|
||||
if (mContentType == ContentType.Applications) {
|
||||
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();
|
||||
if (mContentType == ContentType.Widgets) {
|
||||
PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
|
||||
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
||||
int childCount = layout.getChildCount();
|
||||
if (childCount > 0) {
|
||||
i = numApps +
|
||||
(currentPage * numItemsPerPage) + (childCount / 2);
|
||||
i = (currentPage * numItemsPerPage) + (childCount / 2);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Invalid ContentType");
|
||||
@@ -314,13 +295,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
int getPageForComponent(int index) {
|
||||
if (index < 0) return 0;
|
||||
|
||||
if (index < mApps.size()) {
|
||||
int numItemsPerPage = mCellCountX * mCellCountY;
|
||||
return (index / numItemsPerPage);
|
||||
} else {
|
||||
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
||||
return (index - mApps.size()) / numItemsPerPage;
|
||||
}
|
||||
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
|
||||
return index / numItemsPerPage;
|
||||
}
|
||||
|
||||
/** Restores the page for an item at the specified index */
|
||||
@@ -332,16 +308,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
private void updatePageCounts() {
|
||||
mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
|
||||
(float) (mWidgetCountX * mWidgetCountY));
|
||||
mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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);
|
||||
|
||||
if (!isDataReady()) {
|
||||
if ((!mApps.isEmpty()) && !mWidgets.isEmpty()) {
|
||||
if (!mWidgets.isEmpty()) {
|
||||
post(new Runnable() {
|
||||
// This code triggers requestLayout so must be posted outside of the
|
||||
// layout pass.
|
||||
@@ -438,7 +407,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// When we have exited all apps or are in transition, disregard clicks
|
||||
if (!mLauncher.isAllAppsVisible()
|
||||
if (!mLauncher.isWidgetsViewVisible()
|
||||
|| mLauncher.getWorkspace().isSwitchingState()
|
||||
|| !(v instanceof PagedViewWidget)) return;
|
||||
|
||||
@@ -456,11 +425,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
*/
|
||||
@Override
|
||||
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) {
|
||||
@@ -681,12 +645,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
protected boolean beginDragging(final View v) {
|
||||
if (!super.beginDragging(v)) return false;
|
||||
|
||||
if (v instanceof BubbleTextView) {
|
||||
beginDraggingApplication(v);
|
||||
} else if (v instanceof PagedViewWidget) {
|
||||
if (v instanceof PagedViewWidget) {
|
||||
if (!beginDraggingWidget(v)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Unexpected dragging view: " + v);
|
||||
}
|
||||
|
||||
// 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
|
||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||
while (iter.hasNext()) {
|
||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
||||
AppsCustomizeAsyncTask task = iter.next();
|
||||
task.cancel(false);
|
||||
iter.remove();
|
||||
mDirtyPageContent.set(task.page, true);
|
||||
@@ -886,7 +850,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
// Update the thread priorities given the direction lookahead
|
||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||
while (iter.hasNext()) {
|
||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
||||
AppsCustomizeAsyncTask task = iter.next();
|
||||
int pageIndex = task.page;
|
||||
if ((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) {
|
||||
mPageBackgroundsVisible = visible;
|
||||
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.
|
||||
*/
|
||||
@@ -991,7 +888,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||
int minPageDiff = Integer.MAX_VALUE;
|
||||
while (iter.hasNext()) {
|
||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
||||
AppsCustomizeAsyncTask task = iter.next();
|
||||
minPageDiff = Math.abs(task.page - toPage);
|
||||
}
|
||||
|
||||
@@ -1026,7 +923,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
// Prune all tasks that are no longer needed
|
||||
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
|
||||
while (iter.hasNext()) {
|
||||
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
|
||||
AppsCustomizeAsyncTask task = iter.next();
|
||||
int taskPage = task.page;
|
||||
if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
|
||||
taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
|
||||
@@ -1264,14 +1161,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
cancelAllTasks();
|
||||
|
||||
Context context = getContext();
|
||||
if (mContentType == ContentType.Applications) {
|
||||
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) {
|
||||
if (mContentType == ContentType.Widgets) {
|
||||
for (int j = 0; j < mNumWidgetPages; ++j) {
|
||||
PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
|
||||
mWidgetCountY);
|
||||
@@ -1291,7 +1181,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
if (mContentType == ContentType.Widgets) {
|
||||
syncWidgetPageItems(page, immediate);
|
||||
} 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
|
||||
* 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.
|
||||
@@ -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() {
|
||||
// If we have reset, then we should not continue to restore the previous state
|
||||
mSaveInstanceStateItemIndex = -1;
|
||||
|
||||
if (mContentType != ContentType.Applications) {
|
||||
setContentType(ContentType.Applications);
|
||||
if (mContentType != ContentType.Widgets) {
|
||||
setContentType(ContentType.Widgets);
|
||||
}
|
||||
|
||||
if (mCurrentPage != 0) {
|
||||
@@ -1479,7 +1308,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
|
||||
public void dumpState() {
|
||||
// TODO: Dump information related to current list of Applications, Widgets, etc.
|
||||
AppInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
|
||||
dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
|
||||
}
|
||||
|
||||
@@ -1534,10 +1362,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
|
||||
int stringId = R.string.default_scroll_format;
|
||||
int count = 0;
|
||||
|
||||
if (mContentType == ContentType.Applications) {
|
||||
stringId = R.string.apps_customize_apps_scroll_format;
|
||||
count = mNumAppsPages;
|
||||
} else if (mContentType == ContentType.Widgets) {
|
||||
if (mContentType == ContentType.Widgets) {
|
||||
stringId = R.string.apps_customize_widgets_scroll_format;
|
||||
count = mNumWidgetPages;
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.widget.FrameLayout;
|
||||
public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
|
||||
static final String LOG_TAG = "AppsCustomizeTabHost";
|
||||
|
||||
private static final String APPS_TAB_TAG = "APPS";
|
||||
private static final String WIDGETS_TAB_TAG = "WIDGETS";
|
||||
|
||||
private AppsCustomizePagedView mPagedView;
|
||||
@@ -50,10 +49,6 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
||||
mPagedView.setContentType(type);
|
||||
}
|
||||
|
||||
public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
|
||||
setContentTypeImmediate(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets.set(insets);
|
||||
@@ -78,28 +73,39 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
||||
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.
|
||||
*/
|
||||
public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
|
||||
if (tag.equals(APPS_TAB_TAG)) {
|
||||
return AppsCustomizePagedView.ContentType.Applications;
|
||||
} else if (tag.equals(WIDGETS_TAB_TAG)) {
|
||||
return AppsCustomizePagedView.ContentType.Widgets;
|
||||
}
|
||||
return AppsCustomizePagedView.ContentType.Applications;
|
||||
return AppsCustomizePagedView.ContentType.Widgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tab tag for a given content type.
|
||||
*/
|
||||
public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
|
||||
if (type == AppsCustomizePagedView.ContentType.Applications) {
|
||||
return APPS_TAB_TAG;
|
||||
} else if (type == AppsCustomizePagedView.ContentType.Widgets) {
|
||||
return WIDGETS_TAB_TAG;
|
||||
}
|
||||
return APPS_TAB_TAG;
|
||||
return WIDGETS_TAB_TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +205,7 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
||||
ViewGroup parent = (ViewGroup) getParent();
|
||||
if (parent == null) return;
|
||||
|
||||
View appsView = ((Launcher) getContext()).getAppsView();
|
||||
View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
|
||||
final int count = parent.getChildCount();
|
||||
if (!isChildrenDrawingOrderEnabled()) {
|
||||
@@ -207,7 +214,8 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
|
||||
if (child == this) {
|
||||
break;
|
||||
} else {
|
||||
if (child.getVisibility() == GONE || child == overviewPanel) {
|
||||
if (child.getVisibility() == GONE || child == overviewPanel ||
|
||||
child == appsView) {
|
||||
continue;
|
||||
}
|
||||
child.setVisibility(visibility);
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
@@ -49,7 +50,7 @@ public class BubbleTextView extends TextView {
|
||||
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
|
||||
static final float PADDING_V = 3.0f;
|
||||
|
||||
|
||||
private Drawable mIcon;
|
||||
private final Drawable mBackground;
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
private final HolographicOutlineHelper mOutlineHelper;
|
||||
@@ -62,9 +63,12 @@ public class BubbleTextView extends TextView {
|
||||
|
||||
private float mSlop;
|
||||
|
||||
private int mTextColor;
|
||||
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 mIgnorePressedStateChange;
|
||||
@@ -79,10 +83,19 @@ public class BubbleTextView extends TextView {
|
||||
|
||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.BubbleTextView, defStyle, 0);
|
||||
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();
|
||||
|
||||
if (mCustomShadowsEnabled) {
|
||||
@@ -92,6 +105,12 @@ public class BubbleTextView extends TextView {
|
||||
} else {
|
||||
mBackground = null;
|
||||
}
|
||||
|
||||
// If we are laying out horizontal, then center the text vertically
|
||||
if (mLayoutHorizontal) {
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
}
|
||||
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
|
||||
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
|
||||
@@ -106,9 +125,7 @@ public class BubbleTextView extends TextView {
|
||||
super.onFinishInflate();
|
||||
|
||||
// Ensure we are using the right text size
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
|
||||
}
|
||||
|
||||
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
||||
@@ -119,16 +136,11 @@ public class BubbleTextView extends TextView {
|
||||
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
|
||||
boolean setDefaultPadding, boolean promiseStateChanged) {
|
||||
Bitmap b = info.getIcon(iconCache);
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
|
||||
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
|
||||
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
|
||||
|
||||
setCompoundDrawables(null, iconDrawable, null, null);
|
||||
if (setDefaultPadding) {
|
||||
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
|
||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
||||
}
|
||||
setIcon(iconDrawable, mIconSize, setDefaultPadding ? mIconPaddingSize : -1);
|
||||
if (info.contentDescription != null) {
|
||||
setContentDescription(info.contentDescription);
|
||||
}
|
||||
@@ -141,13 +153,7 @@ public class BubbleTextView extends TextView {
|
||||
}
|
||||
|
||||
public void applyFromApplicationInfo(AppInfo info) {
|
||||
LauncherAppState app = LauncherAppState.getInstance();
|
||||
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);
|
||||
setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize, mIconPaddingSize);
|
||||
setText(info.title);
|
||||
if (info.contentDescription != null) {
|
||||
setContentDescription(info.contentDescription);
|
||||
@@ -155,7 +161,6 @@ public class BubbleTextView extends TextView {
|
||||
setTag(info);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean setFrame(int left, int top, int right, int 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() {
|
||||
Drawable top = getCompoundDrawables()[1];
|
||||
if (top instanceof FastBitmapDrawable) {
|
||||
((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
|
||||
if (mIcon instanceof FastBitmapDrawable) {
|
||||
((FastBitmapDrawable) mIcon).setPressed(isPressed() || mStayPressed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,10 +339,9 @@ public class BubbleTextView extends TextView {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
if (mBackground != null) mBackground.setCallback(this);
|
||||
Drawable top = getCompoundDrawables()[1];
|
||||
|
||||
if (top instanceof PreloadIconDrawable) {
|
||||
((PreloadIconDrawable) top).applyPreloaderTheme(getPreloaderTheme());
|
||||
if (mIcon instanceof PreloadIconDrawable) {
|
||||
((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme());
|
||||
}
|
||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
}
|
||||
@@ -358,11 +371,6 @@ public class BubbleTextView extends TextView {
|
||||
} else {
|
||||
super.setTextColor(res.getColor(android.R.color.transparent));
|
||||
}
|
||||
mIsTextVisible = visible;
|
||||
}
|
||||
|
||||
public boolean isTextVisible() {
|
||||
return mIsTextVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -385,15 +393,13 @@ public class BubbleTextView extends TextView {
|
||||
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
|
||||
info.getInstallProgress() : 0)) : 100;
|
||||
|
||||
Drawable[] drawables = getCompoundDrawables();
|
||||
Drawable top = drawables[1];
|
||||
if (top != null) {
|
||||
if (mIcon != null) {
|
||||
final PreloadIconDrawable preloadDrawable;
|
||||
if (top instanceof PreloadIconDrawable) {
|
||||
preloadDrawable = (PreloadIconDrawable) top;
|
||||
if (mIcon instanceof PreloadIconDrawable) {
|
||||
preloadDrawable = (PreloadIconDrawable) mIcon;
|
||||
} else {
|
||||
preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
|
||||
setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
|
||||
preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
|
||||
setIcon(preloadDrawable, mIconSize, -1);
|
||||
}
|
||||
|
||||
preloadDrawable.setLevel(progressLevel);
|
||||
@@ -417,4 +423,23 @@ public class BubbleTextView extends TextView {
|
||||
}
|
||||
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 allAppsNumRows;
|
||||
int allAppsNumCols;
|
||||
// TODO(winsonc): to be used with the grid layout
|
||||
int allAppsRowsSize;
|
||||
int searchBarSpaceWidthPx;
|
||||
int searchBarSpaceHeightPx;
|
||||
int pageIndicatorHeightPx;
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
@@ -47,7 +48,6 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.FolderInfo.FolderListener;
|
||||
import com.android.launcher3.Workspace.ItemOperator;
|
||||
|
||||
@@ -220,7 +220,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
|
||||
return false;
|
||||
}
|
||||
|
||||
mLauncher.getWorkspace().beginDragShared(v, this);
|
||||
mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
|
||||
|
||||
mCurrentDragInfo = item;
|
||||
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) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
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
|
||||
if (mNextPage != INVALID_PAGE) return false;
|
||||
// When we have exited all apps or are in transition, disregard long clicks
|
||||
if (!mLauncher.isAllAppsVisible() ||
|
||||
if (!mLauncher.isWidgetsViewVisible() ||
|
||||
mLauncher.getWorkspace().isSwitchingState()) return false;
|
||||
// Return if global dragging is not enabled
|
||||
if (!mLauncher.isDraggingEnabled()) return false;
|
||||
|
||||
@@ -131,8 +131,8 @@ public class WidgetPreviewLoader {
|
||||
private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
|
||||
private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
|
||||
|
||||
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
|
||||
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
|
||||
private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
|
||||
private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>();
|
||||
|
||||
private final Context mContext;
|
||||
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
|
||||
public void announceForAccessibility(CharSequence text) {
|
||||
// Don't announce if apps is on top of us.
|
||||
if (!mLauncher.isAllAppsVisible()) {
|
||||
if (!mLauncher.isAppsViewVisible()) {
|
||||
super.announceForAccessibility(text);
|
||||
}
|
||||
}
|
||||
@@ -1816,7 +1816,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
@Override
|
||||
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
|
||||
if (!mLauncher.isAllAppsVisible()) {
|
||||
if (!mLauncher.isAppsViewVisible()) {
|
||||
final Folder openFolder = getOpenFolder();
|
||||
if (openFolder != null) {
|
||||
return openFolder.requestFocus(direction, previouslyFocusedRect);
|
||||
@@ -1837,7 +1837,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
@Override
|
||||
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
|
||||
if (!mLauncher.isAllAppsVisible()) {
|
||||
if (!mLauncher.isAppsViewVisible()) {
|
||||
final Folder openFolder = getOpenFolder();
|
||||
if (openFolder != null) {
|
||||
openFolder.addFocusables(views, direction);
|
||||
@@ -2046,8 +2046,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
// If this is a text view, use its drawable instead
|
||||
if (v instanceof TextView) {
|
||||
TextView tv = (TextView) v;
|
||||
Drawable d = tv.getCompoundDrawables()[1];
|
||||
Drawable d = getTextViewIcon((TextView) v);
|
||||
Rect bounds = getDrawableBounds(d);
|
||||
bmpWidth = bounds.width();
|
||||
bmpHeight = bounds.height();
|
||||
@@ -2348,7 +2347,7 @@ public class Workspace extends SmoothPagedView
|
||||
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
|
||||
} else {
|
||||
if (layerViews != null) {
|
||||
layerViews.put(cl, Launcher.BUILD_LAYER);
|
||||
layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
|
||||
}
|
||||
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
|
||||
LauncherViewPropertyAnimator alphaAnim =
|
||||
@@ -2400,8 +2399,8 @@ public class Workspace extends SmoothPagedView
|
||||
if (layerViews != null) {
|
||||
// If layerViews is not null, we add these views, and indicate that
|
||||
// the caller can manage layer state.
|
||||
layerViews.put(hotseat, Launcher.BUILD_AND_SET_LAYER);
|
||||
layerViews.put(overviewPanel, Launcher.BUILD_AND_SET_LAYER);
|
||||
layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||
layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||
} else {
|
||||
// Otherwise let the animator handle layer management.
|
||||
hotseatAlpha.withLayer();
|
||||
@@ -2430,7 +2429,7 @@ public class Workspace extends SmoothPagedView
|
||||
if (layerViews != null) {
|
||||
// If layerViews is not null, we add these views, and indicate that
|
||||
// the caller can manage layer state.
|
||||
layerViews.put(searchBar, Launcher.BUILD_AND_SET_LAYER);
|
||||
layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
|
||||
} else {
|
||||
// Otherwise let the animator handle layer management.
|
||||
searchBarAlpha.withLayer();
|
||||
@@ -2583,6 +2582,19 @@ public class Workspace extends SmoothPagedView
|
||||
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.
|
||||
*
|
||||
@@ -2598,7 +2610,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
destCanvas.save();
|
||||
if (v instanceof TextView) {
|
||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
||||
Drawable d = getTextViewIcon((TextView) v);
|
||||
Rect bounds = getDrawableBounds(d);
|
||||
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
|
||||
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
|
||||
@@ -2635,7 +2647,7 @@ public class Workspace extends SmoothPagedView
|
||||
|
||||
int padding = expectedPadding.get();
|
||||
if (v instanceof TextView) {
|
||||
Drawable d = ((TextView) v).getCompoundDrawables()[1];
|
||||
Drawable d = getTextViewIcon((TextView) v);
|
||||
Rect bounds = getDrawableBounds(d);
|
||||
b = Bitmap.createBitmap(bounds.width() + padding,
|
||||
bounds.height() + padding, Bitmap.Config.ARGB_8888);
|
||||
@@ -2716,11 +2728,12 @@ public class Workspace extends SmoothPagedView
|
||||
beginDragShared(child, this, accessible);
|
||||
}
|
||||
|
||||
public void beginDragShared(View child, DragSource source) {
|
||||
beginDragShared(child, source, false);
|
||||
public void beginDragShared(View child, DragSource source, boolean accessible) {
|
||||
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.setPressed(false);
|
||||
|
||||
@@ -2745,11 +2758,23 @@ public class Workspace extends SmoothPagedView
|
||||
Point dragVisualizeOffset = null;
|
||||
Rect dragRect = null;
|
||||
if (child instanceof BubbleTextView) {
|
||||
BubbleTextView icon = (BubbleTextView) child;
|
||||
int iconSize = grid.iconSizePx;
|
||||
int top = child.getPaddingTop();
|
||||
int left = (bmpWidth - iconSize) / 2;
|
||||
int right = left + 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;
|
||||
// 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.
|
||||
@@ -2831,18 +2856,6 @@ public class Workspace extends SmoothPagedView
|
||||
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() {
|
||||
return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
|
||||
(mState == State.NORMAL || mState == State.SPRING_LOADED));
|
||||
@@ -4769,7 +4782,7 @@ public class Workspace extends SmoothPagedView
|
||||
updates.contains(info)) {
|
||||
ShortcutInfo si = (ShortcutInfo) info;
|
||||
BubbleTextView shortcut = (BubbleTextView) v;
|
||||
boolean oldPromiseState = shortcut.getCompoundDrawables()[1]
|
||||
boolean oldPromiseState = getTextViewIcon(shortcut)
|
||||
instanceof PreloadIconDrawable;
|
||||
shortcut.applyFromShortcutInfo(si, mIconCache, true,
|
||||
si.isPromise() != oldPromiseState);
|
||||
|
||||
Reference in New Issue
Block a user