From 840c1cf2c0cb3884e2628ac8f6e4d48e9fc469c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C6=B0ng=20Phan?= Date: Thu, 1 Oct 2020 00:23:56 +0700 Subject: [PATCH] Cherish:Clean slimrecents from Android 10 --- .../settings/preferences/FODIconPicker.java | 355 -- .../preferences/SlimShortcutPickerHelper.java | 181 - .../dslv/ActionListViewSettings.java | 989 ------ .../preferences/dslv/DragSortController.java | 488 --- .../preferences/dslv/DragSortItemView.java | 118 - .../preferences/dslv/DragSortListView.java | 3067 ----------------- .../dslv/SimpleFloatViewManager.java | 106 - 7 files changed, 5304 deletions(-) delete mode 100644 src/com/cherish/settings/preferences/FODIconPicker.java delete mode 100644 src/com/cherish/settings/preferences/SlimShortcutPickerHelper.java delete mode 100644 src/com/cherish/settings/preferences/dslv/ActionListViewSettings.java delete mode 100644 src/com/cherish/settings/preferences/dslv/DragSortController.java delete mode 100644 src/com/cherish/settings/preferences/dslv/DragSortItemView.java delete mode 100644 src/com/cherish/settings/preferences/dslv/DragSortListView.java delete mode 100644 src/com/cherish/settings/preferences/dslv/SimpleFloatViewManager.java diff --git a/src/com/cherish/settings/preferences/FODIconPicker.java b/src/com/cherish/settings/preferences/FODIconPicker.java deleted file mode 100644 index 8528423..0000000 --- a/src/com/cherish/settings/preferences/FODIconPicker.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2020 CherishOS 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.cherish.settings.preferences; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.provider.Settings; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageButton; - -import androidx.core.content.res.TypedArrayUtils; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; - -import com.android.settings.R; - -import com.android.settingslib.Utils; -import com.android.settingslib.widget.LayoutPreference; - -public class FODIconPicker extends LayoutPreference { - - private boolean mAllowDividerAbove; - private boolean mAllowDividerBelow; - - private View mRootView; - - private static ImageButton Button0; - private static ImageButton Button1; - private static ImageButton Button2; - private static ImageButton Button3; - private static ImageButton Button4; - private static ImageButton Button5; - private static ImageButton Button6; - private static ImageButton Button7; - private static ImageButton Button8; - private static ImageButton Button9; - private static ImageButton Button10; - private static ImageButton Button11; - private static ImageButton Button12; - private static ImageButton Button13; - private static ImageButton Button14; - private static ImageButton Button15; - private static ImageButton Button16; - private static ImageButton Button17; - private static ImageButton Button18; - private static ImageButton Button19; - private static ImageButton Button20; - - private static final String TAG = "FODIconPicker"; - - public FODIconPicker(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs, 0 /* defStyleAttr */); - } - - public FODIconPicker(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs, defStyleAttr); - } - - private void init(Context context, AttributeSet attrs, int defStyleAttr) { - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Preference); - mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove, - R.styleable.Preference_allowDividerAbove, false); - mAllowDividerBelow = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerBelow, - R.styleable.Preference_allowDividerBelow, false); - a.recycle(); - - a = context.obtainStyledAttributes( - attrs, R.styleable.Preference, defStyleAttr, 0); - int layoutResource = a.getResourceId(R.styleable.Preference_android_layout, 0); - if (layoutResource == 0) { - throw new IllegalArgumentException("LayoutPreference requires a layout to be defined"); - } - a.recycle(); - - // Need to create view now so that findViewById can be called immediately. - final View view = LayoutInflater.from(getContext()) - .inflate(layoutResource, null, false); - setView(view, context); - } - - private void setView(View view, Context context) { - setLayoutResource(R.layout.layout_preference_frame); - mRootView = view; - setShouldDisableView(false); - Button0 = findViewById(R.id.fodicon0_button); - Button1 = findViewById(R.id.fodicon1_button); - Button2 = findViewById(R.id.fodicon2_button); - Button3 = findViewById(R.id.fodicon3_button); - Button4 = findViewById(R.id.fodicon4_button); - Button5 = findViewById(R.id.fodicon5_button); - Button6 = findViewById(R.id.fodicon6_button); - Button7 = findViewById(R.id.fodicon7_button); - Button8 = findViewById(R.id.fodicon8_button); - Button9 = findViewById(R.id.fodicon9_button); - Button10 = findViewById(R.id.fodicon10_button); - Button11 = findViewById(R.id.fodicon11_button); - Button12 = findViewById(R.id.fodicon12_button); - Button13 = findViewById(R.id.fodicon13_button); - Button14 = findViewById(R.id.fodicon14_button); - Button15 = findViewById(R.id.fodicon15_button); - Button16 = findViewById(R.id.fodicon16_button); - Button17 = findViewById(R.id.fodicon17_button); - Button18 = findViewById(R.id.fodicon18_button); - Button19 = findViewById(R.id.fodicon19_button); - Button20 = findViewById(R.id.fodicon20_button); - - int defaultfodicon = Settings.System.getInt( - context.getContentResolver(), Settings.System.FOD_ICON, 0); - if (defaultfodicon==0) { - updateHighlightedItem(Button0, context); - } else if (defaultfodicon == 1) { - updateHighlightedItem(Button1, context); - } else if (defaultfodicon == 2) { - updateHighlightedItem(Button2, context); - } else if (defaultfodicon == 3) { - updateHighlightedItem(Button3, context); - } else if (defaultfodicon == 4) { - updateHighlightedItem(Button4, context); - } else if (defaultfodicon == 5) { - updateHighlightedItem(Button5, context); - } else if (defaultfodicon == 6) { - updateHighlightedItem(Button6, context); - } else if (defaultfodicon == 7) { - updateHighlightedItem(Button7, context); - } else if (defaultfodicon == 8) { - updateHighlightedItem(Button8, context); - } else if (defaultfodicon == 9) { - updateHighlightedItem(Button9, context); - } else if (defaultfodicon == 10) { - updateHighlightedItem(Button10, context); - } else if (defaultfodicon == 11) { - updateHighlightedItem(Button11, context); - } else if (defaultfodicon == 12) { - updateHighlightedItem(Button12, context); - } else if (defaultfodicon == 13) { - updateHighlightedItem(Button13, context); - } else if (defaultfodicon == 14) { - updateHighlightedItem(Button14, context); - } else if (defaultfodicon == 15) { - updateHighlightedItem(Button15, context); - } else if (defaultfodicon == 16) { - updateHighlightedItem(Button16, context); - } else if (defaultfodicon == 17) { - updateHighlightedItem(Button17, context); - } else if (defaultfodicon == 18) { - updateHighlightedItem(Button18, context); - } else if (defaultfodicon == 19) { - updateHighlightedItem(Button19, context); - } else if (defaultfodicon == 20) { - updateHighlightedItem(Button20, context); - } - - Button0.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(0, context); - updateHighlightedItem(Button0, context); - } - }); - Button1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(1, context); - updateHighlightedItem(Button1, context); - } - }); - Button2.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(2, context); - updateHighlightedItem(Button2, context); - } - }); - Button3.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(3, context); - updateHighlightedItem(Button3, context); - } - }); - Button4.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(4, context); - updateHighlightedItem(Button4, context); - } - }); - Button5.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(5, context); - updateHighlightedItem(Button5, context); - } - }); - Button6.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(6, context); - updateHighlightedItem(Button6, context); - } - }); - Button7.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(7, context); - updateHighlightedItem(Button7, context); - } - }); - Button8.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(8, context); - updateHighlightedItem(Button8, context); - } - }); - Button9.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(9, context); - updateHighlightedItem(Button9, context); - } - }); - Button10.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(10, context); - updateHighlightedItem(Button10, context); - } - }); - Button11.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(11, context); - updateHighlightedItem(Button11, context); - } - }); - Button12.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(12, context); - updateHighlightedItem(Button12, context); - } - }); - Button13.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(13, context); - updateHighlightedItem(Button13, context); - } - }); - Button14.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(14, context); - updateHighlightedItem(Button14, context); - } - }); - Button15.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(15, context); - updateHighlightedItem(Button15, context); - } - }); - Button16.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(16, context); - updateHighlightedItem(Button16, context); - } - }); - Button17.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(17, context); - updateHighlightedItem(Button17, context); - } - }); - Button18.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(18, context); - updateHighlightedItem(Button18, context); - } - }); - Button19.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(19, context); - updateHighlightedItem(Button19, context); - } - }); - Button20.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - updateSettings(20, context); - updateHighlightedItem(Button20, context); - } - }); - } - - private void updateSettings(int fodicon, Context context) { - Settings.System.putInt(context.getContentResolver(), Settings.System.FOD_ICON, fodicon); - } - - private void updateHighlightedItem(ImageButton activebutton, Context context) { - int defaultcolor = context.getResources().getColor(R.color.fod_item_background_stroke_color); - ColorStateList defaulttint = ColorStateList.valueOf(defaultcolor); - Button0.setBackgroundTintList(defaulttint); - Button1.setBackgroundTintList(defaulttint); - Button2.setBackgroundTintList(defaulttint); - Button3.setBackgroundTintList(defaulttint); - Button4.setBackgroundTintList(defaulttint); - Button5.setBackgroundTintList(defaulttint); - Button6.setBackgroundTintList(defaulttint); - Button7.setBackgroundTintList(defaulttint); - Button8.setBackgroundTintList(defaulttint); - Button9.setBackgroundTintList(defaulttint); - Button10.setBackgroundTintList(defaulttint); - Button11.setBackgroundTintList(defaulttint); - Button12.setBackgroundTintList(defaulttint); - Button13.setBackgroundTintList(defaulttint); - Button14.setBackgroundTintList(defaulttint); - Button15.setBackgroundTintList(defaulttint); - Button16.setBackgroundTintList(defaulttint); - Button17.setBackgroundTintList(defaulttint); - Button18.setBackgroundTintList(defaulttint); - Button19.setBackgroundTintList(defaulttint); - Button20.setBackgroundTintList(defaulttint); - activebutton.setBackgroundTintList(Utils.getColorAttr(getContext(), android.R.attr.colorAccent)); - } -} diff --git a/src/com/cherish/settings/preferences/SlimShortcutPickerHelper.java b/src/com/cherish/settings/preferences/SlimShortcutPickerHelper.java deleted file mode 100644 index 88a139a..0000000 --- a/src/com/cherish/settings/preferences/SlimShortcutPickerHelper.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2014 SlimRoms 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.cherish.settings.preferences; - -import android.app.Activity; -import android.content.Intent; -import android.content.Intent.ShortcutIconResource; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.Log; - -import com.android.settings.R; - -import com.android.internal.util.slim.AppHelper; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; - -import java.util.ArrayList; - -public class SlimShortcutPickerHelper { - - public static final int REQUEST_PICK_SHORTCUT = 100; - public static final int REQUEST_PICK_APPLICATION = 101; - public static final int REQUEST_CREATE_SHORTCUT = 102; - - private Activity mParent; - private OnPickListener mListener; - private PackageManager mPackageManager; - private int lastFragmentId; - - public interface OnPickListener { - void shortcutPicked(String uri, String friendlyName, Bitmap bmp, boolean isApplication); - } - - public SlimShortcutPickerHelper(Activity parent, OnPickListener listener) { - mParent = parent; - mPackageManager = mParent.getPackageManager(); - mListener = listener; - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_OK) { - switch (requestCode) { - case REQUEST_PICK_APPLICATION: - completeSetCustomApp(data); - break; - case REQUEST_CREATE_SHORTCUT: - completeSetCustomShortcut(data); - break; - case REQUEST_PICK_SHORTCUT: - processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT); - break; - } - } - } - - public void pickShortcut(int fragmentId) { - pickShortcut(fragmentId, false); - } - - public void pickShortcut(int fragmentId, boolean fullAppsOnly) { - lastFragmentId = fragmentId; - - if (fullAppsOnly) { - Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - - Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); - pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent); - startFragmentOrActivity(pickIntent, REQUEST_PICK_APPLICATION); - } else { - Bundle bundle = new Bundle(); - - ArrayList shortcutNames = new ArrayList(); - shortcutNames.add(mParent.getString(R.string.shortcuts_applications)); - bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); - - ArrayList shortcutIcons = new ArrayList(); - shortcutIcons.add(ShortcutIconResource.fromContext(mParent, - android.R.drawable.sym_def_app_icon)); - bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); - - Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); - pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT)); - pickIntent.putExtra(Intent.EXTRA_TITLE, mParent.getText( - R.string.shortcuts_select_custom_app_title)); - pickIntent.putExtras(bundle); - startFragmentOrActivity(pickIntent, REQUEST_PICK_SHORTCUT); - } - } - - private void startFragmentOrActivity(Intent pickIntent, int requestCode) { - if (lastFragmentId == 0 || !(mParent instanceof FragmentActivity)) { - mParent.startActivityForResult(pickIntent, requestCode); - } else { - final FragmentActivity fa = (FragmentActivity) mParent; - Fragment cFrag = fa.getSupportFragmentManager().findFragmentById(lastFragmentId); - if (cFrag != null) { - fa.startActivityFromFragment(cFrag, pickIntent, requestCode); - } else { - mParent.startActivityForResult(pickIntent, requestCode); } - } - } - - private void processShortcut(Intent intent, - int requestCodeApplication, int requestCodeShortcut) { - // Handle case where user selected "Applications" - String applicationName = mParent.getResources().getString(R.string.shortcuts_applications); - String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); - - if (applicationName != null && applicationName.equals(shortcutName)) { - Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - - Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); - pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent); - startFragmentOrActivity(pickIntent, requestCodeApplication); - } else { - startFragmentOrActivity(intent, requestCodeShortcut); - } - } - - private void completeSetCustomApp(Intent data) { - mListener.shortcutPicked(data.toUri(0), - AppHelper.getFriendlyActivityName(mParent, mPackageManager, data, false), null, true); - } - - private void completeSetCustomShortcut(Intent data) { - Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); - /* preserve shortcut name, we want to restore it later */ - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, data.getStringExtra( - Intent.EXTRA_SHORTCUT_NAME)); - String appUri = intent.toUri(0); - appUri = appUri.replaceAll("com.android.contacts.action.QUICK_CONTACT", - "android.intent.action.VIEW"); - - // Check if icon is present - Bitmap bmp = null; - Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); - if (extra != null && extra instanceof Bitmap) { - bmp = (Bitmap) extra; - } - // No icon till now check if icon resource is present - if (bmp == null) { - extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); - if (extra != null && extra instanceof Intent.ShortcutIconResource) { - try { - Intent.ShortcutIconResource iconResource = (ShortcutIconResource) extra; - Resources resources = - mPackageManager.getResourcesForApplication(iconResource.packageName); - final int id = resources.getIdentifier(iconResource.resourceName, null, null); - bmp = BitmapFactory.decodeResource(resources, id); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - mListener.shortcutPicked(appUri, - AppHelper.getFriendlyShortcutName(mParent, mPackageManager, intent), bmp, false); - } - -} diff --git a/src/com/cherish/settings/preferences/dslv/ActionListViewSettings.java b/src/com/cherish/settings/preferences/dslv/ActionListViewSettings.java deleted file mode 100644 index e365c2b..0000000 --- a/src/com/cherish/settings/preferences/dslv/ActionListViewSettings.java +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Copyright (C) 2014 Slimroms - * Copyright (C) 2015-2017 Android Ice Cold 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.cherish.settings.preferences.dslv; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.provider.MediaStore; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.ListView; -import android.widget.Toast; - -import com.android.internal.util.slim.ActionConfig; -import com.android.internal.util.slim.ActionConstants; -import com.android.internal.util.slim.ActionHelper; -import com.android.internal.util.slim.ImageHelper; -import com.android.internal.util.slim.DeviceUtils; -import com.android.internal.util.slim.DeviceUtils.FilteredDeviceFeaturesArray; - -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.ListFragment; -import androidx.fragment.app.FragmentManager; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.cherish.settings.preferences.SlimShortcutPickerHelper; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; - -public class ActionListViewSettings extends ListFragment implements - SlimShortcutPickerHelper.OnPickListener { - - private static final int DLG_SHOW_ACTION_DIALOG = 0; - private static final int DLG_SHOW_ICON_PICKER = 1; - private static final int DLG_DELETION_NOT_ALLOWED = 2; - private static final int DLG_SHOW_HELP_SCREEN = 3; - private static final int DLG_RESET_TO_DEFAULT = 4; - - private static final int MENU_HELP = Menu.FIRST; - private static final int MENU_ADD = MENU_HELP + 1; - private static final int MENU_RESET = MENU_ADD + 1; - - private static final int NAV_BAR = 0; - private static final int PIE = 1; - private static final int PIE_SECOND = 2; - private static final int NAV_RING = 3; - private static final int LOCKSCREEN_SHORTCUT = 4; - private static final int POWER_MENU_SHORTCUT = 5; - private static final int SHAKE_EVENTS_DISABLED = 6; - private static final int RECENT_APP_SIDEBAR = 7; - - private static final int DEFAULT_MAX_ACTION_NUMBER = 5; - - public static final int REQUEST_PICK_CUSTOM_ICON = 1000; - - private int mActionMode; - private int mMaxAllowedActions; - private boolean mUseAppPickerOnly; - private boolean mUseFullAppsOnly; - private boolean mDisableLongpress; - private boolean mDisableIconPicker; - private boolean mDisableDeleteLastEntry; - - private TextView mDisableMessage; - - private ActionConfigsAdapter mActionConfigsAdapter; - - private ArrayList mActionConfigs; - private ActionConfig mActionConfig; - - private boolean mAdditionalFragmentAttached; - private String mAdditionalFragment; - private View mDivider; - - private int mPendingIndex = -1; - private boolean mPendingLongpress; - private boolean mPendingNewAction; - - private String[] mActionDialogValues; - private String[] mActionDialogEntries; - private String mActionValuesKey; - private String mActionEntriesKey; - - private Activity mActivity; - private SlimShortcutPickerHelper mPicker; - - private File mImageTmp; - - private DragSortListView.DropListener onDrop = - new DragSortListView.DropListener() { - @Override - public void drop(int from, int to) { - ActionConfig item = mActionConfigsAdapter.getItem(from); - - mActionConfigsAdapter.remove(item); - mActionConfigsAdapter.insert(item, to); - - setConfig(mActionConfigs, false); - } - }; - - private DragSortListView.RemoveListener onRemove = - new DragSortListView.RemoveListener() { - @Override - public void remove(int which) { - ActionConfig item = mActionConfigsAdapter.getItem(which); - mActionConfigsAdapter.remove(item); - if (mDisableDeleteLastEntry && mActionConfigs.size() == 0) { - mActionConfigsAdapter.add(item); - showDialogInner(DLG_DELETION_NOT_ALLOWED, 0, false, false); - } else { - deleteIconFileIfPresent(item, true); - setConfig(mActionConfigs, false); - if (mActionConfigs.size() == 0) { - showDisableMessage(true); - } - } - } - }; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - return inflater.inflate(R.layout.dslv_action_list_view_main, container, false); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - mActivity = activity; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - Resources res = getResources(); - - if (false) { - // Tell Lint these arrays are used - int unused = R.array.shortcut_action_values; - unused = R.array.shortcut_action_entries; - } - - mActionMode = getArguments().getInt("actionMode", NAV_BAR); - mMaxAllowedActions = getArguments().getInt("maxAllowedActions", DEFAULT_MAX_ACTION_NUMBER); - mAdditionalFragment = getArguments().getString("fragment", null); - mActionValuesKey = getArguments().getString("actionValues", "shortcut_action_values"); - mActionEntriesKey = getArguments().getString("actionEntries", "shortcut_action_entries"); - mDisableLongpress = getArguments().getBoolean("disableLongpress", false); - mUseAppPickerOnly = getArguments().getBoolean("useAppPickerOnly", false); - mUseFullAppsOnly = getArguments().getBoolean("useOnlyFullAppPicker", false); - mDisableIconPicker = getArguments().getBoolean("disableIconPicker", false); - mDisableIconPicker = true; - mDisableDeleteLastEntry = getArguments().getBoolean("disableDeleteLastEntry", false); - - mDisableMessage = (TextView) view.findViewById(R.id.disable_message); - - FilteredDeviceFeaturesArray finalActionDialogArray = new FilteredDeviceFeaturesArray(); - finalActionDialogArray = DeviceUtils.filterUnsupportedDeviceFeatures(mActivity, - res.getStringArray(res.getIdentifier( - mActionValuesKey, "array", "com.android.settings")), - res.getStringArray(res.getIdentifier( - mActionEntriesKey, "array", "com.android.settings"))); - mActionDialogValues = finalActionDialogArray.values; - mActionDialogEntries = finalActionDialogArray.entries; - - mPicker = new SlimShortcutPickerHelper(mActivity, this); - - mImageTmp = new File(mActivity.getCacheDir() - + File.separator + "shortcut.tmp"); - - DragSortListView listView = (DragSortListView) getListView(); - - listView.setDropListener(onDrop); - listView.setRemoveListener(onRemove); - - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView arg0, View arg1, int arg2, - long arg3) { - if (mUseFullAppsOnly) { - if (mPicker != null) { - mPendingIndex = arg2; - mPendingLongpress = false; - mPendingNewAction = false; - mPicker.pickShortcut(getId(), true); - } - } else if (!mUseAppPickerOnly) { - showDialogInner(DLG_SHOW_ACTION_DIALOG, arg2, false, false); - } else { - if (mPicker != null) { - mPendingIndex = arg2; - mPendingLongpress = false; - mPendingNewAction = false; - mPicker.pickShortcut(getId()); - } - } - } - }); - - if (!mDisableLongpress) { - listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, - long arg3) { - if (mUseFullAppsOnly) { - if (mPicker != null) { - mPendingIndex = arg2; - mPendingLongpress = true; - mPendingNewAction = false; - mPicker.pickShortcut(getId(), true); - } - } else if (!mUseAppPickerOnly) { - showDialogInner(DLG_SHOW_ACTION_DIALOG, arg2, true, false); - } else { - if (mPicker != null) { - mPendingIndex = arg2; - mPendingLongpress = true; - mPendingNewAction = false; - mPicker.pickShortcut(getId()); - } - } - return true; - } - }); - } - - mActionConfigs = getConfig(); - - if (mActionConfigs != null) { - mActionConfigsAdapter = new ActionConfigsAdapter(mActivity, mActionConfigs); - setListAdapter(mActionConfigsAdapter); - showDisableMessage(mActionConfigs.size() == 0); - } - - mDivider = (View) view.findViewById(R.id.divider); - loadAdditionalFragment(); - - // get shared preference - SharedPreferences preferences = - mActivity.getSharedPreferences("dslv_settings", Activity.MODE_PRIVATE); - if (!preferences.getBoolean("first_help_shown_mode_" + mActionMode, false)) { - preferences.edit() - .putBoolean("first_help_shown_mode_" + mActionMode, true).commit(); - showDialogInner(DLG_SHOW_HELP_SCREEN, 0, false, false); - } - - setHasOptionsMenu(true); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - if (mAdditionalFragmentAttached) { - FragmentManager fragmentManager = getFragmentManager(); - Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container); - if (fragment != null && !fragmentManager.isDestroyed()) { - fragmentManager.beginTransaction().remove(fragment).commit(); - } - } - } - - private void loadAdditionalFragment() { - if (mAdditionalFragment != null && !mAdditionalFragment.isEmpty()) { - try { - Class classAdditionalFragment = Class.forName(mAdditionalFragment); - Fragment fragment = (Fragment) classAdditionalFragment.newInstance(); - getFragmentManager().beginTransaction() - .replace(R.id.fragment_container, fragment).commit(); - if (mDivider != null) { - mDivider.setVisibility(View.VISIBLE); - } - mAdditionalFragmentAttached = true; - } catch (Exception e) { - mAdditionalFragmentAttached = false; - e.printStackTrace(); - } - } - } - - @Override - public void shortcutPicked(String action, - String description, Bitmap bmp, boolean isApplication) { - if (mPendingIndex == -1) { - return; - } - if (bmp != null && !mPendingLongpress) { - // Icon is present, save it for future use and add the file path to the action. - String fileName = mActivity.getFilesDir() - + File.separator + "shortcut_" + System.currentTimeMillis() + ".png"; - try { - FileOutputStream out = new FileOutputStream(fileName); - bmp.compress(Bitmap.CompressFormat.PNG, 100, out); - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - action = action + "?hasExtraIcon=" + fileName; - File image = new File(fileName); - image.setReadable(true, false); - } - } - if (mPendingNewAction) { - addNewAction(action, description); - } else { - updateAction(action, description, null, mPendingIndex, mPendingLongpress); - } - mPendingLongpress = false; - mPendingNewAction = false; - mPendingIndex = -1; - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_OK) { - if (requestCode == SlimShortcutPickerHelper.REQUEST_PICK_SHORTCUT - || requestCode == SlimShortcutPickerHelper.REQUEST_PICK_APPLICATION - || requestCode == SlimShortcutPickerHelper.REQUEST_CREATE_SHORTCUT) { - mPicker.onActivityResult(requestCode, resultCode, data); - - } else if (requestCode == REQUEST_PICK_CUSTOM_ICON && mPendingIndex != -1) { - if (mImageTmp.length() == 0 || !mImageTmp.exists()) { - mPendingIndex = -1; - Toast.makeText(mActivity, - getResources().getString(R.string.shortcut_image_not_valid), - Toast.LENGTH_LONG).show(); - return; - } - File image = new File(mActivity.getFilesDir() + File.separator - + "shortcut_" + System.currentTimeMillis() + ".png"); - String path = image.getAbsolutePath(); - mImageTmp.renameTo(image); - image.setReadable(true, false); - updateAction(null, null, path, mPendingIndex, false); - mPendingIndex = -1; - } - } else { - if (mImageTmp.exists()) { - mImageTmp.delete(); - } - mPendingLongpress = false; - mPendingNewAction = false; - mPendingIndex = -1; - } - super.onActivityResult(requestCode, resultCode, data); - } - - private void updateAction(String action, String description, String icon, - int which, boolean longpress) { - - if (!longpress && checkForDuplicateMainNavActions(action)) { - return; - } - - ActionConfig actionConfig = mActionConfigsAdapter.getItem(which); - mActionConfigsAdapter.remove(actionConfig); - - if (!longpress) { - deleteIconFileIfPresent(actionConfig, false); - } - - if (icon != null) { - actionConfig.setIcon(icon); - } else { - if (longpress) { - actionConfig.setLongpressAction(action); - actionConfig.setLongpressActionDescription(description); - } else { - deleteIconFileIfPresent(actionConfig, true); - actionConfig.setClickAction(action); - actionConfig.setClickActionDescription(description); - actionConfig.setIcon(ActionConstants.ICON_EMPTY); - } - } - - mActionConfigsAdapter.insert(actionConfig, which); - showDisableMessage(false); - setConfig(mActionConfigs, false); - } - - private boolean checkForDuplicateMainNavActions(String action) { - ActionConfig actionConfig; - for (int i = 0; i < mActionConfigs.size(); i++) { - actionConfig = mActionConfigsAdapter.getItem(i); - if (actionConfig.getClickAction().equals(action)) { - Toast.makeText(mActivity, - getResources().getString(R.string.shortcut_duplicate_entry), - Toast.LENGTH_LONG).show(); - return true; - } - } - return false; - } - - private void deleteIconFileIfPresent(ActionConfig action, boolean deleteShortCutIcon) { - File oldImage = new File(action.getIcon()); - if (oldImage.exists()) { - oldImage.delete(); - } - oldImage = new File(action.getClickAction().replaceAll(".*?hasExtraIcon=", "")); - if (oldImage.exists() && deleteShortCutIcon) { - oldImage.delete(); - } - } - - private void showDisableMessage(boolean show) { - if (mDisableMessage == null || mDisableDeleteLastEntry) { - return; - } - if (show) { - mDisableMessage.setVisibility(View.VISIBLE); - } else { - mDisableMessage.setVisibility(View.GONE); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case MENU_ADD: - if (mActionConfigs.size() == mMaxAllowedActions) { - Toast.makeText(mActivity, - getResources().getString(R.string.shortcut_action_max), - Toast.LENGTH_LONG).show(); - break; - } - if (mUseFullAppsOnly) { - if (mPicker != null) { - mPendingIndex = 0; - mPendingLongpress = false; - mPendingNewAction = true; - mPicker.pickShortcut(getId(), true); - } - } else if (!mUseAppPickerOnly) { - showDialogInner(DLG_SHOW_ACTION_DIALOG, 0, false, true); - } else { - if (mPicker != null) { - mPendingIndex = 0; - mPendingLongpress = false; - mPendingNewAction = true; - mPicker.pickShortcut(getId()); - } - } - break; - case MENU_RESET: - showDialogInner(DLG_RESET_TO_DEFAULT, 0, false, true); - break; - case MENU_HELP: - showDialogInner(DLG_SHOW_HELP_SCREEN, 0, false, true); - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - menu.add(0, MENU_HELP, 0, R.string.help) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(0, MENU_RESET, 0, R.string.shortcut_action_reset) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(0, MENU_ADD, 0, R.string.shortcut_action_add) - .setIcon(R.drawable.ic_menu_add) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - - } - - private void addNewAction(String action, String description) { - if (checkForDuplicateMainNavActions(action)) { - return; - } - ActionConfig actionConfig = new ActionConfig( - action, description, - ActionConstants.ACTION_NULL, getResources().getString(R.string.shortcut_action_none), - ActionConstants.ICON_EMPTY); - - mActionConfigsAdapter.add(actionConfig); - showDisableMessage(false); - setConfig(mActionConfigs, false); - } - - private ArrayList getConfig() { - switch (mActionMode) { -/* Disabled for now till all features are back. Enable it step per step!!!!!! - case LOCKSCREEN_SHORTCUT: - return ActionHelper.getLockscreenShortcutConfig(mActivity); - case NAV_BAR: - return ActionHelper.getNavBarConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - case NAV_RING: - return ActionHelper.getNavRingConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - case PIE: - return ActionHelper.getPieConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - case PIE_SECOND: - return ActionHelper.getPieSecondLayerConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - case POWER_MENU_SHORTCUT: - return PolicyHelper.getPowerMenuConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - case SHAKE_EVENTS_DISABLED: - return ActionHelper.getDisabledShakeApps(mActivity); -*/ - case RECENT_APP_SIDEBAR: - return ActionHelper.getRecentAppSidebarConfigWithDescription( - mActivity, mActionValuesKey, mActionEntriesKey); - } - return null; - } - - private void setConfig(ArrayList actionConfigs, boolean reset) { - switch (mActionMode) { -/* Disabled for now till all features are back. Enable it step per step!!!!!! - case LOCKSCREEN_SHORTCUT: - ActionHelper.setLockscreenShortcutConfig(mActivity, actionConfigs, reset); - break; - case NAV_BAR: - ActionHelper.setNavBarConfig(mActivity, actionConfigs, reset); - break; - case NAV_RING: - ActionHelper.setNavRingConfig(mActivity, actionConfigs, reset); - break; - case PIE: - ActionHelper.setPieConfig(mActivity, actionConfigs, reset); - break; - case PIE_SECOND: - ActionHelper.setPieSecondLayerConfig(mActivity, actionConfigs, reset); - break; - case POWER_MENU_SHORTCUT: - PolicyHelper.setPowerMenuConfig(mActivity, actionConfigs, reset); - break; - case SHAKE_EVENTS_DISABLED: - ActionHelper.setDisabledShakeApps(mActivity, actionConfigs, reset); - break; -*/ - case RECENT_APP_SIDEBAR: - ActionHelper.setRecentAppSidebarConfig(mActivity, actionConfigs, reset); - break; - } - } - - private class ViewHolder { - public TextView longpressActionDescriptionView; - public ImageView iconView; - } - - private class ActionConfigsAdapter extends ArrayAdapter { - - private int mIconColor; - - public ActionConfigsAdapter(Context context, List clickActionDescriptions) { - super(context, R.layout.dslv_action_list_view_item, - R.id.click_action_description, clickActionDescriptions); - - // Themed resources - int[] attrs = new int[] { - android.R.attr.textColorPrimary, - }; - TypedArray ta = context.getTheme().obtainStyledAttributes(attrs); - mIconColor = ta.getColor(0, 0xff808080); - ta.recycle(); - } - - public View getView(final int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - - if (v != convertView && v != null) { - ViewHolder holder = new ViewHolder(); - - TextView longpressActionDecription = - (TextView) v.findViewById(R.id.longpress_action_description); - ImageView icon = (ImageView) v.findViewById(R.id.icon); - - if (mDisableLongpress) { - longpressActionDecription.setVisibility(View.GONE); - } else { - holder.longpressActionDescriptionView = longpressActionDecription; - } - - holder.iconView = icon; - - v.setTag(holder); - } - - ViewHolder holder = (ViewHolder) v.getTag(); - - if (!mDisableLongpress) { - holder.longpressActionDescriptionView.setText( - getResources().getString(R.string.shortcut_action_longpress) - + " " + getItem(position).getLongpressActionDescription()); - } - - Drawable d = null; - String iconUri = getItem(position).getIcon(); - if (mActionMode == POWER_MENU_SHORTCUT) { -/* Disabled for now till slims power menu is back!!!!!!!!!!!!!! - d = ImageHelper.resize( - mActivity, PolicyHelper.getPowerMenuIconImage(mActivity, - getItem(position).getClickAction(), - iconUri, false), 36); */ - } else { - d = ImageHelper.resize( - mActivity, ActionHelper.getActionIconImage(mActivity, - getItem(position).getClickAction(), - iconUri), 36); - } - - if (iconUri != null && iconUri.startsWith(ActionConstants.SYSTEM_ICON_IDENTIFIER)) { - d.setTint(mIconColor); - } - holder.iconView.setImageDrawable(d); - - if (!mDisableIconPicker && holder.iconView.getDrawable() != null) { - holder.iconView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mPendingIndex = position; - showDialogInner(DLG_SHOW_ICON_PICKER, 0, false, false); - } - }); - } - - return v; - } - } - - private void showDialogInner(int id, int which, boolean longpress, boolean newAction) { - DialogFragment newFragment = - MyAlertDialogFragment.newInstance(id, which, longpress, newAction); - newFragment.setTargetFragment(this, 0); - newFragment.show(getFragmentManager(), "dialog " + id); - } - - public static class MyAlertDialogFragment extends DialogFragment { - - private int mIconColor; - - public static MyAlertDialogFragment newInstance(int id, - int which, boolean longpress, boolean newAction) { - MyAlertDialogFragment frag = new MyAlertDialogFragment(); - Bundle args = new Bundle(); - args.putInt("id", id); - args.putInt("which", which); - args.putBoolean("longpress", longpress); - args.putBoolean("newAction", newAction); - frag.setArguments(args); - return frag; - } - - ActionListViewSettings getOwner() { - return (ActionListViewSettings) getTargetFragment(); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - int id = getArguments().getInt("id"); - final int which = getArguments().getInt("which"); - final boolean longpress = getArguments().getBoolean("longpress"); - final boolean newAction = getArguments().getBoolean("newAction"); - switch (id) { - case DLG_RESET_TO_DEFAULT: - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.shortcut_action_reset) - .setMessage(R.string.reset_message) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // first delete custom icons in case they exist - ArrayList actionConfigs = getOwner().getConfig(); - for (int i = 0; i < actionConfigs.size(); i++) { - getOwner().deleteIconFileIfPresent(actionConfigs.get(i), true); - } - - // reset provider values and action adapter to default - getOwner().setConfig(null, true); - getOwner().mActionConfigsAdapter.clear(); - - // Add the new default objects fetched from @getConfig() - actionConfigs = getOwner().getConfig(); - final int newConfigsSize = actionConfigs.size(); - for (int i = 0; i < newConfigsSize; i++) { - getOwner().mActionConfigsAdapter.add(actionConfigs.get(i)); - } - - // dirty helper if actionConfigs list has no entries - // to proper update the content. .notifyDatSetChanged() - // does not work in this case. - if (newConfigsSize == 0) { - ActionConfig emptyAction = - new ActionConfig(null, null, null, null, null); - getOwner().mActionConfigsAdapter.add(emptyAction); - getOwner().mActionConfigsAdapter.remove(emptyAction); - } - getOwner().showDisableMessage(newConfigsSize == 0); - } - }) - .create(); - case DLG_SHOW_HELP_SCREEN: - Resources res = getResources(); - String finalHelpMessage; - String actionMode; - String icon = ""; - switch (getOwner().mActionMode) { - case LOCKSCREEN_SHORTCUT: - case POWER_MENU_SHORTCUT: - actionMode = res.getString(R.string.shortcut_action_help_shortcut); - break; - case SHAKE_EVENTS_DISABLED: - actionMode = res.getString(R.string.shortcut_action_help_app); - break; - case NAV_BAR: - case NAV_RING: - case PIE: - case PIE_SECOND: - case RECENT_APP_SIDEBAR: - default: - actionMode = res.getString(R.string.shortcut_action_help_button); - break; - } - if (!getOwner().mDisableIconPicker) { - icon = res.getString(R.string.shortcut_action_help_icon); - } - finalHelpMessage = res.getString( - R.string.shortcut_action_help_main, actionMode, icon); - if (!getOwner().mDisableDeleteLastEntry) { - finalHelpMessage += " " + res.getString( - getOwner().mActionMode == PIE_SECOND - ? R.string.shortcut_action_help_pie_second_layer_delete_last_entry - : R.string.shortcut_action_help_delete_last_entry, actionMode); - } - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.help) - .setMessage(finalHelpMessage) - .setNegativeButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }) - .create(); - case DLG_DELETION_NOT_ALLOWED: - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.shortcut_action_warning) - .setMessage(R.string.shortcut_action_warning_message) - .setNegativeButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }) - .create(); - case DLG_SHOW_ACTION_DIALOG: - int title; - if (longpress) { - title = R.string.shortcut_action_select_action_longpress; - } else if (newAction) { - title = R.string.shortcut_action_select_action_newaction; - } else { - title = R.string.shortcut_action_select_action; - } - - // for normal press action we filter out null value - // due it does not make sense to set a null action - // on normal press action - String[] values = null; - String[] entries = null; - if (!longpress) { - List finalEntriesList = new ArrayList(); - List finalValuesList = new ArrayList(); - - for (int i = 0; i < getOwner().mActionDialogValues.length; i++) { - if (!getOwner().mActionDialogValues[i] - .equals(ActionConstants.ACTION_NULL)) { - finalEntriesList.add(getOwner().mActionDialogEntries[i]); - finalValuesList.add(getOwner().mActionDialogValues[i]); - } - } - - entries = finalEntriesList.toArray(new String[finalEntriesList.size()]); - values = finalValuesList.toArray(new String[finalValuesList.size()]); - } - - final String[] finalDialogValues = - longpress ? getOwner().mActionDialogValues : values; - final String[] finalDialogEntries = - longpress ? getOwner().mActionDialogEntries : entries; - - return new AlertDialog.Builder(getActivity()) - .setTitle(title) - .setNegativeButton(R.string.cancel, null) - .setItems(finalDialogEntries, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - if (finalDialogValues[item].equals(ActionConstants.ACTION_APP)) { - if (getOwner().mPicker != null) { - getOwner().mPendingIndex = which; - getOwner().mPendingLongpress = longpress; - getOwner().mPendingNewAction = newAction; - getOwner().mPicker.pickShortcut(getOwner().getId()); - } - } else { - if (newAction) { - getOwner().addNewAction(finalDialogValues[item], - finalDialogEntries[item]); - } else { - getOwner().updateAction(finalDialogValues[item], - finalDialogEntries[item], - null, which, longpress); - } - } - } - }) - .create(); - case DLG_SHOW_ICON_PICKER: - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.shortcuts_icon_picker_type) - .setNegativeButton(R.string.cancel, null) - .setItems(R.array.icon_types, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - switch(which) { - case 0: // Default - getOwner().updateAction(null, null, - ActionConstants.ICON_EMPTY, - getOwner().mPendingIndex, false); - getOwner().mPendingIndex = -1; - break; - case 1: // System defaults - /* - ListView list = new ListView(getActivity()); - list.setAdapter(new IconAdapter(mIconColor)); - final Dialog holoDialog = new Dialog(getActivity()); - holoDialog.setTitle( - R.string.shortcuts_icon_picker_choose_icon_title); - holoDialog.setContentView(list); - list.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, - int position, long id) { - IconAdapter adapter = (IconAdapter) parent.getAdapter(); - getOwner().updateAction(null, null, - adapter.getItemReference(position), - getOwner().mPendingIndex, false); - getOwner().mPendingIndex = -1; - holoDialog.cancel(); - } - }); - holoDialog.show(); - break; - case 2: // Custom user icon - */ - Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); - intent.setType("image/*"); - intent.putExtra("crop", "true"); - intent.putExtra("scale", true); - intent.putExtra("outputFormat", - Bitmap.CompressFormat.PNG.toString()); - intent.putExtra("aspectX", 100); - intent.putExtra("aspectY", 100); - intent.putExtra("outputX", 100); - intent.putExtra("outputY", 100); - try { - getOwner().mImageTmp.createNewFile(); - getOwner().mImageTmp.setWritable(true, false); - intent.putExtra(MediaStore.EXTRA_OUTPUT, - Uri.fromFile(getOwner().mImageTmp)); - intent.putExtra("return-data", false); - getOwner().startActivityForResult( - intent, REQUEST_PICK_CUSTOM_ICON); - } catch (IOException e) { - e.printStackTrace(); - } catch (ActivityNotFoundException e) { - e.printStackTrace(); - } - break; - } - } - }) - .create(); - } - throw new IllegalArgumentException("unknown id " + id); - } - - @Override - public void onCancel(DialogInterface dialog) { - - } - - public class IconAdapter extends BaseAdapter { - - TypedArray icons; - String[] labels; - int color; - - public IconAdapter(int iconColor) { - labels = getResources().getStringArray(R.array.shortcut_icon_picker_labels); - icons = getResources().obtainTypedArray(R.array.shortcut_icon_picker_icons); - color = iconColor; - } - - @Override - public Object getItem(int position) { - return icons.getDrawable(position); - } - - @Override - public long getItemId(int position) { - return 0; - } - - @Override - public int getCount() { - return labels.length; - } - - public String getItemReference(int position) { - String name = icons.getString(position); - int separatorIndex = name.lastIndexOf(File.separator); - int periodIndex = name.lastIndexOf('.'); - return ActionConstants.SYSTEM_ICON_IDENTIFIER - + name.substring(separatorIndex + 1, periodIndex); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View iView = convertView; - if (convertView == null) { - iView = View.inflate(getActivity(), android.R.layout.simple_list_item_1, null); - } - TextView tt = (TextView) iView.findViewById(android.R.id.text1); - tt.setText(labels[position]); - Drawable ic = ((Drawable) getItem(position)).mutate(); - ic.setTint(color); - tt.setCompoundDrawablePadding(15); - tt.setCompoundDrawablesWithIntrinsicBounds(ic, null, null, null); - return iView; - } - } - } -} diff --git a/src/com/cherish/settings/preferences/dslv/DragSortController.java b/src/com/cherish/settings/preferences/dslv/DragSortController.java deleted file mode 100644 index 83733cf..0000000 --- a/src/com/cherish/settings/preferences/dslv/DragSortController.java +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Copyright 2012 Carl Bauer - * Copyright (C) 2014 SlimRoms 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.cherish.settings.preferences.dslv; - -import android.graphics.Point; -import android.view.GestureDetector; -import android.view.HapticFeedbackConstants; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.widget.AdapterView; - -/** - * Class that starts and stops item drags on a {@link DragSortListView} - * based on touch gestures. This class also inherits from - * {@link SimpleFloatViewManager}, which provides basic float View - * creation. - * - * An instance of this class is meant to be passed to the methods - * {@link DragSortListView#setTouchListener()} and - * {@link DragSortListView#setFloatViewManager()} of your - * {@link DragSortListView} instance. - */ -public class DragSortController extends SimpleFloatViewManager - implements View.OnTouchListener, GestureDetector.OnGestureListener { - - /** - * Drag init mode enum. - */ - public static final int ON_DOWN = 0; - public static final int ON_DRAG = 1; - public static final int ON_LONG_PRESS = 2; - - private int mDragInitMode = ON_DOWN; - - private boolean mSortEnabled = true; - - /** - * Remove mode enum. - */ - public static final int CLICK_REMOVE = 0; - public static final int FLING_REMOVE = 1; - - /** - * The current remove mode. - */ - private int mRemoveMode; - - private boolean mRemoveEnabled = false; - private boolean mIsRemoving = false; - - private GestureDetector mDetector; - - private GestureDetector mFlingRemoveDetector; - - private int mTouchSlop; - - public static final int MISS = -1; - - private int mHitPos = MISS; - private int mFlingHitPos = MISS; - - private int mClickRemoveHitPos = MISS; - - private int[] mTempLoc = new int[2]; - - private int mItemX; - private int mItemY; - - private int mCurrX; - private int mCurrY; - - private boolean mDragging = false; - - private float mFlingSpeed = 500f; - - private int mDragHandleId; - - private int mClickRemoveId; - - private int mFlingHandleId; - private boolean mCanDrag; - - private DragSortListView mDslv; - private int mPositionX; - - /** - * Calls {@link #DragSortController(DragSortListView, int)} with a - * 0 drag handle id, FLING_RIGHT_REMOVE remove mode, - * and ON_DOWN drag init. By default, sorting is enabled, and - * removal is disabled. - * - * @param dslv The DSLV instance - */ - public DragSortController(DragSortListView dslv) { - this(dslv, 0, ON_DOWN, FLING_REMOVE); - } - - public DragSortController(DragSortListView dslv, - int dragHandleId, int dragInitMode, int removeMode) { - this(dslv, dragHandleId, dragInitMode, removeMode, 0); - } - - public DragSortController(DragSortListView dslv, int dragHandleId, - int dragInitMode, int removeMode, int clickRemoveId) { - this(dslv, dragHandleId, dragInitMode, removeMode, clickRemoveId, 0); - } - - /** - * By default, sorting is enabled, and removal is disabled. - * - * @param dslv The DSLV instance - * @param dragHandleId The resource id of the View that represents - * the drag handle in a list item. - */ - public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, - int removeMode, int clickRemoveId, int flingHandleId) { - super(dslv); - mDslv = dslv; - mDetector = new GestureDetector(dslv.getContext(), this); - mFlingRemoveDetector = new GestureDetector(dslv.getContext(), mFlingRemoveListener); - mFlingRemoveDetector.setIsLongpressEnabled(false); - mTouchSlop = ViewConfiguration.get(dslv.getContext()).getScaledTouchSlop(); - mDragHandleId = dragHandleId; - mClickRemoveId = clickRemoveId; - mFlingHandleId = flingHandleId; - setRemoveMode(removeMode); - setDragInitMode(dragInitMode); - } - - - public int getDragInitMode() { - return mDragInitMode; - } - - /** - * Set how a drag is initiated. Needs to be one of - * {@link ON_DOWN}, {@link ON_DRAG}, or {@link ON_LONG_PRESS}. - * - * @param mode The drag init mode. - */ - public void setDragInitMode(int mode) { - mDragInitMode = mode; - } - - /** - * Enable/Disable list item sorting. Disabling is useful if only item - * removal is desired. Prevents drags in the vertical direction. - * - * @param enabled Set true to enable list - * item sorting. - */ - public void setSortEnabled(boolean enabled) { - mSortEnabled = enabled; - } - - public boolean isSortEnabled() { - return mSortEnabled; - } - - /** - * One of {@link CLICK_REMOVE}, {@link FLING_RIGHT_REMOVE}, - * {@link FLING_LEFT_REMOVE}, - * {@link SLIDE_RIGHT_REMOVE}, or {@link SLIDE_LEFT_REMOVE}. - */ - public void setRemoveMode(int mode) { - mRemoveMode = mode; - } - - public int getRemoveMode() { - return mRemoveMode; - } - - /** - * Enable/Disable item removal without affecting remove mode. - */ - public void setRemoveEnabled(boolean enabled) { - mRemoveEnabled = enabled; - } - - public boolean isRemoveEnabled() { - return mRemoveEnabled; - } - - /** - * Set the resource id for the View that represents the drag - * handle in a list item. - * - * @param id An android resource id. - */ - public void setDragHandleId(int id) { - mDragHandleId = id; - } - - /** - * Set the resource id for the View that represents the fling - * handle in a list item. - * - * @param id An android resource id. - */ - public void setFlingHandleId(int id) { - mFlingHandleId = id; - } - - /** - * Set the resource id for the View that represents click - * removal button. - * - * @param id An android resource id. - */ - public void setClickRemoveId(int id) { - mClickRemoveId = id; - } - - /** - * Sets flags to restrict certain motions of the floating View - * based on DragSortController settings (such as remove mode). - * Starts the drag on the DragSortListView. - * - * @param position The list item position (includes headers). - * @param deltaX Touch x-coord minus left edge of floating View. - * @param deltaY Touch y-coord minus top edge of floating View. - * - * @return True if drag started, false otherwise. - */ - public boolean startDrag(int position, int deltaX, int deltaY) { - - int dragFlags = 0; - if (mSortEnabled && !mIsRemoving) { - dragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y; - } - if (mRemoveEnabled && mIsRemoving) { - dragFlags |= DragSortListView.DRAG_POS_X; - dragFlags |= DragSortListView.DRAG_NEG_X; - } - - mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), dragFlags, deltaX, - deltaY); - return mDragging; - } - - @Override - public boolean onTouch(View v, MotionEvent ev) { - if (!mDslv.isDragEnabled() || mDslv.listViewIntercepted()) { - return false; - } - - mDetector.onTouchEvent(ev); - if (mRemoveEnabled && mDragging && mRemoveMode == FLING_REMOVE) { - mFlingRemoveDetector.onTouchEvent(ev); - } - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mCurrX = (int) ev.getX(); - mCurrY = (int) ev.getY(); - break; - case MotionEvent.ACTION_UP: - if (mRemoveEnabled && mIsRemoving) { - int x = mPositionX >= 0 ? mPositionX : -mPositionX; - int removePoint = mDslv.getWidth() / 2; - if (x > removePoint) { - mDslv.stopDragWithVelocity(true, 0); - } - } - case MotionEvent.ACTION_CANCEL: - mIsRemoving = false; - mDragging = false; - break; - } - - return false; - } - - /** - * Overrides to provide fading when slide removal is enabled. - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - - if (mRemoveEnabled && mIsRemoving) { - mPositionX = position.x; - } - } - - /** - * Get the position to start dragging based on the ACTION_DOWN - * MotionEvent. This function simply calls - * {@link #dragHandleHitPosition(MotionEvent)}. Override - * to change drag handle behavior; - * this function is called internally when an ACTION_DOWN - * event is detected. - * - * @param ev The ACTION_DOWN MotionEvent. - * - * @return The list position to drag if a drag-init gesture is - * detected; MISS if unsuccessful. - */ - public int startDragPosition(MotionEvent ev) { - return dragHandleHitPosition(ev); - } - - public int startFlingPosition(MotionEvent ev) { - return mRemoveMode == FLING_REMOVE ? flingHandleHitPosition(ev) : MISS; - } - - /** - * Checks for the touch of an item's drag handle (specified by - * {@link #setDragHandleId(int)}), and returns that item's position - * if a drag handle touch was detected. - * - * @param ev The ACTION_DOWN MotionEvent. - - * @return The list position of the item whose drag handle was - * touched; MISS if unsuccessful. - */ - public int dragHandleHitPosition(MotionEvent ev) { - return viewIdHitPosition(ev, mDragHandleId); - } - - public int flingHandleHitPosition(MotionEvent ev) { - return viewIdHitPosition(ev, mFlingHandleId); - } - - public int viewIdHitPosition(MotionEvent ev, int id) { - final int x = (int) ev.getX(); - final int y = (int) ev.getY(); - - int touchPos = mDslv.pointToPosition(x, y); // includes headers/footers - - final int numHeaders = mDslv.getHeaderViewsCount(); - final int numFooters = mDslv.getFooterViewsCount(); - final int count = mDslv.getCount(); - - // Log.d("mobeta", "touch down on position " + itemnum); - // We're only interested if the touch was on an - // item that's not a header or footer. - if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders - && touchPos < (count - numFooters)) { - final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition()); - final int rawX = (int) ev.getRawX(); - final int rawY = (int) ev.getRawY(); - - View dragBox = id == 0 ? item : (View) item.findViewById(id); - if (dragBox != null) { - dragBox.getLocationOnScreen(mTempLoc); - - if (rawX > mTempLoc[0] && rawY > mTempLoc[1] && - rawX < mTempLoc[0] + dragBox.getWidth() && - rawY < mTempLoc[1] + dragBox.getHeight()) { - - mItemX = item.getLeft(); - mItemY = item.getTop(); - - return touchPos; - } - } - } - - return MISS; - } - - @Override - public boolean onDown(MotionEvent ev) { - if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) { - mClickRemoveHitPos = viewIdHitPosition(ev, mClickRemoveId); - } - - mHitPos = startDragPosition(ev); - if (mHitPos != MISS && mDragInitMode == ON_DOWN) { - startDrag(mHitPos, (int) ev.getX() - mItemX, (int) ev.getY() - mItemY); - } - - mIsRemoving = false; - mCanDrag = true; - mPositionX = 0; - mFlingHitPos = startFlingPosition(ev); - - return true; - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - - final int x1 = (int) e1.getX(); - final int y1 = (int) e1.getY(); - final int x2 = (int) e2.getX(); - final int y2 = (int) e2.getY(); - final int deltaX = x2 - mItemX; - final int deltaY = y2 - mItemY; - - if (mCanDrag && !mDragging && (mHitPos != MISS || mFlingHitPos != MISS)) { - if (mHitPos != MISS) { - if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) { - startDrag(mHitPos, deltaX, deltaY); - } else if (mDragInitMode != ON_DOWN - && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) { - mIsRemoving = true; - startDrag(mFlingHitPos, deltaX, deltaY); - } - } else if (mFlingHitPos != MISS) { - if (Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) { - mIsRemoving = true; - startDrag(mFlingHitPos, deltaX, deltaY); - } else if (Math.abs(y2 - y1) > mTouchSlop) { - mCanDrag = false; // if started to scroll the list then - // don't allow sorting nor fling-removing - } - } - } - // return whatever - return false; - } - - @Override - public void onLongPress(MotionEvent e) { - // Log.d("mobeta", "lift listener long pressed"); - if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) { - mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY); - } - } - - // complete the OnGestureListener interface - @Override - public final boolean onFling(MotionEvent e1, - MotionEvent e2, float velocityX, float velocityY) { - return false; - } - - // complete the OnGestureListener interface - @Override - public boolean onSingleTapUp(MotionEvent ev) { - if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) { - if (mClickRemoveHitPos != MISS) { - mDslv.removeItem(mClickRemoveHitPos - mDslv.getHeaderViewsCount()); - } - } - return true; - } - - // complete the OnGestureListener interface - @Override - public void onShowPress(MotionEvent ev) { - // do nothing - } - - private GestureDetector.OnGestureListener mFlingRemoveListener = - new GestureDetector.SimpleOnGestureListener() { - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - // Log.d("mobeta", "on fling remove called"); - if (mRemoveEnabled && mIsRemoving) { - int w = mDslv.getWidth(); - int minPos = w / 5; - if (velocityX > mFlingSpeed) { - if (mPositionX > -minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } else if (velocityX < -mFlingSpeed) { - if (mPositionX < minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } - mIsRemoving = false; - } - return false; - } - }; - -} diff --git a/src/com/cherish/settings/preferences/dslv/DragSortItemView.java b/src/com/cherish/settings/preferences/dslv/DragSortItemView.java deleted file mode 100644 index 173d589..0000000 --- a/src/com/cherish/settings/preferences/dslv/DragSortItemView.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2012 Carl Bauer - * Copyright (C) 2014 SlimRoms 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.cherish.settings.preferences.dslv; - -import android.content.Context; -import android.view.Gravity; -import android.view.View; -import android.view.View.MeasureSpec; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.util.Log; - -/** - * Lightweight ViewGroup that wraps list items obtained from user's - * ListAdapter. ItemView expects a single child that has a definite - * height (i.e. the child's layout height is not MATCH_PARENT). - * The width of - * ItemView will always match the width of its child (that is, - * the width MeasureSpec given to ItemView is passed directly - * to the child, and the ItemView measured width is set to the - * child's measured width). The height of ItemView can be anything; - * the - * - * - * The purpose of this class is to optimize slide - * shuffle animations. - */ -public class DragSortItemView extends ViewGroup { - - private int mGravity = Gravity.TOP; - - public DragSortItemView(Context context) { - super(context); - - // always init with standard ListView layout params - setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - //setClipChildren(true); - } - - public void setGravity(int gravity) { - mGravity = gravity; - } - - public int getGravity() { - return mGravity; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final View child = getChildAt(0); - - if (child == null) { - return; - } - - if (mGravity == Gravity.TOP) { - child.layout(0, 0, getMeasuredWidth(), child.getMeasuredHeight()); - } else { - child.layout(0, getMeasuredHeight() - child.getMeasuredHeight(), - getMeasuredWidth(), getMeasuredHeight()); - } - } - - /** - * - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - int height = MeasureSpec.getSize(heightMeasureSpec); - int width = MeasureSpec.getSize(widthMeasureSpec); - - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - - final View child = getChildAt(0); - if (child == null) { - setMeasuredDimension(0, width); - return; - } - - if (child.isLayoutRequested()) { - // Always let child be as tall as it wants. - measureChild(child, widthMeasureSpec, - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - } - - if (heightMode == MeasureSpec.UNSPECIFIED) { - ViewGroup.LayoutParams lp = getLayoutParams(); - - if (lp.height > 0) { - height = lp.height; - } else { - height = child.getMeasuredHeight(); - } - } - - setMeasuredDimension(width, height); - } - -} diff --git a/src/com/cherish/settings/preferences/dslv/DragSortListView.java b/src/com/cherish/settings/preferences/dslv/DragSortListView.java deleted file mode 100644 index 23c9dc4..0000000 --- a/src/com/cherish/settings/preferences/dslv/DragSortListView.java +++ /dev/null @@ -1,3067 +0,0 @@ -/* - * Copyright 2012 Carl Bauer - * Copyright (C) 2014 SlimRoms 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.cherish.settings.preferences.dslv; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.Environment; -import android.os.SystemClock; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.util.SparseIntArray; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.BaseAdapter; -import android.widget.Checkable; -import android.widget.ListAdapter; -import android.widget.ListView; - -import com.android.settings.R; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; - -/** - * ListView subclass that mediates drag and drop resorting of items. - * - * - * @author heycosmo - * - */ -public class DragSortListView extends ListView { - - /** - * The View that floats above the ListView and represents - * the dragged item. - */ - private View mFloatView; - - /** - * The float View location. First based on touch location - * and given deltaX and deltaY. Then restricted by callback - * to FloatViewManager.onDragFloatView(). Finally restricted - * by bounds of DSLV. - */ - private Point mFloatLoc = new Point(); - - private Point mTouchLoc = new Point(); - - /** - * The middle (in the y-direction) of the floating View. - */ - private int mFloatViewMid; - - /** - * Flag to make sure float View isn't measured twice - */ - private boolean mFloatViewOnMeasured = false; - - /** - * Watch the Adapter for data changes. Cancel a drag if - * coincident with a change. - */ - private DataSetObserver mObserver; - - /** - * Transparency for the floating View (XML attribute). - */ - private float mFloatAlpha = 1.0f; - private float mCurrFloatAlpha = 1.0f; - - /** - * While drag-sorting, the current position of the floating - * View. If dropped, the dragged item will land in this position. - */ - private int mFloatPos; - - /** - * The first expanded ListView position that helps represent - * the drop slot tracking the floating View. - */ - private int mFirstExpPos; - - /** - * The second expanded ListView position that helps represent - * the drop slot tracking the floating View. This can equal - * mFirstExpPos if there is no slide shuffle occurring; otherwise - * it is equal to mFirstExpPos + 1. - */ - private int mSecondExpPos; - - /** - * Flag set if slide shuffling is enabled. - */ - private boolean mAnimate = false; - - /** - * The user dragged from this position. - */ - private int mSrcPos; - - /** - * Offset (in x) within the dragged item at which the user - * picked it up (or first touched down with the digitalis). - */ - private int mDragDeltaX; - - /** - * Offset (in y) within the dragged item at which the user - * picked it up (or first touched down with the digitalis). - */ - private int mDragDeltaY; - - - /** - * The difference (in x) between screen coordinates and coordinates - * in this view. - */ - private int mOffsetX; - - /** - * The difference (in y) between screen coordinates and coordinates - * in this view. - */ - private int mOffsetY; - - /** - * A listener that receives callbacks whenever the floating View - * hovers over a new position. - */ - private DragListener mDragListener; - - /** - * A listener that receives a callback when the floating View - * is dropped. - */ - private DropListener mDropListener; - - /** - * A listener that receives a callback when the floating View - * (or more precisely the originally dragged item) is removed - * by one of the provided gestures. - */ - private RemoveListener mRemoveListener; - - /** - * Enable/Disable item dragging - * - * @attr name dslv:drag_enabled - */ - private boolean mDragEnabled = true; - - /** - * Drag state enum. - */ - private final static int IDLE = 0; - private final static int REMOVING = 1; - private final static int DROPPING = 2; - private final static int STOPPED = 3; - private final static int DRAGGING = 4; - - private int mDragState = IDLE; - - /** - * Height in pixels to which the originally dragged item - * is collapsed during a drag-sort. Currently, this value - * must be greater than zero. - */ - private int mItemHeightCollapsed = 1; - - /** - * Height of the floating View. Stored for the purpose of - * providing the tracking drop slot. - */ - private int mFloatViewHeight; - - /** - * Convenience member. See above. - */ - private int mFloatViewHeightHalf; - - /** - * Save the given width spec for use in measuring children - */ - private int mWidthMeasureSpec = 0; - - /** - * Sample Views ultimately used for calculating the height - * of ListView items that are off-screen. - */ - private View[] mSampleViewTypes = new View[1]; - - /** - * Drag-scroll encapsulator! - */ - private DragScroller mDragScroller; - - /** - * Determines the start of the upward drag-scroll region - * at the top of the ListView. Specified by a fraction - * of the ListView height, thus screen resolution agnostic. - */ - private float mDragUpScrollStartFrac = 1.0f / 3.0f; - - /** - * Determines the start of the downward drag-scroll region - * at the bottom of the ListView. Specified by a fraction - * of the ListView height, thus screen resolution agnostic. - */ - private float mDragDownScrollStartFrac = 1.0f / 3.0f; - - /** - * The following are calculated from the above fracs. - */ - private int mUpScrollStartY; - private int mDownScrollStartY; - private float mDownScrollStartYF; - private float mUpScrollStartYF; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragUpScrollHeight; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragDownScrollHeight; - - /** - * Maximum drag-scroll speed in pixels per ms. Only used with - * default linear drag-scroll profile. - */ - private float mMaxScrollSpeed = 0.5f; - - /** - * Defines the scroll speed during a drag-scroll. User can - * provide their own; this default is a simple linear profile - * where scroll speed increases linearly as the floating View - * nears the top/bottom of the ListView. - */ - private DragScrollProfile mScrollProfile = new DragScrollProfile() { - @Override - public float getSpeed(float w, long t) { - return mMaxScrollSpeed * w; - } - }; - - /** - * Current touch x. - */ - private int mX; - - /** - * Current touch y. - */ - private int mY; - - /** - * Last touch x. - */ - private int mLastX; - - /** - * Last touch y. - */ - private int mLastY; - - /** - * The touch y-coord at which drag started - */ - private int mDragStartY; - - /** - * Drag flag bit. Floating View can move in the positive - * x direction. - */ - public final static int DRAG_POS_X = 0x1; - - /** - * Drag flag bit. Floating View can move in the negative - * x direction. - */ - public final static int DRAG_NEG_X = 0x2; - - /** - * Drag flag bit. Floating View can move in the positive - * y direction. This is subtle. What this actually means is - * that, if enabled, the floating View can be dragged below its starting - * position. Remove in favor of upper-bounding item position? - */ - public final static int DRAG_POS_Y = 0x4; - - /** - * Drag flag bit. Floating View can move in the negative - * y direction. This is subtle. What this actually means is - * that the floating View can be dragged above its starting - * position. Remove in favor of lower-bounding item position? - */ - public final static int DRAG_NEG_Y = 0x8; - - /** - * Flags that determine limits on the motion of the - * floating View. See flags above. - */ - private int mDragFlags = 0; - - /** - * Last call to an on*TouchEvent was a call to - * onInterceptTouchEvent. - */ - private boolean mLastCallWasIntercept = false; - - /** - * A touch event is in progress. - */ - private boolean mInTouchEvent = false; - - /** - * Let the user customize the floating View. - */ - private FloatViewManager mFloatViewManager = null; - - /** - * Given to ListView to cancel its action when a drag-sort - * begins. - */ - private MotionEvent mCancelEvent; - - /** - * Enum telling where to cancel the ListView action when a - * drag-sort begins - */ - private static final int NO_CANCEL = 0; - private static final int ON_TOUCH_EVENT = 1; - private static final int ON_INTERCEPT_TOUCH_EVENT = 2; - - /** - * Where to cancel the ListView action when a - * drag-sort begins - */ - private int mCancelMethod = NO_CANCEL; - - /** - * Determines when a slide shuffle animation starts. That is, - * defines how close to the edge of the drop slot the floating - * View must be to initiate the slide. - */ - private float mSlideRegionFrac = 0.25f; - - /** - * Number between 0 and 1 indicating the relative location of - * a sliding item (only used if drag-sort animations - * are turned on). Nearly 1 means the item is - * at the top of the slide region (nearly full blank item - * is directly below). - */ - private float mSlideFrac = 0.0f; - - /** - * Wraps the user-provided ListAdapter. This is used to wrap each - * item View given by the user inside another View (currenly - * a RelativeLayout) which - * expands and collapses to simulate the item shuffling. - */ - private AdapterWrapper mAdapterWrapper; - - /** - * Turn on custom debugger. - */ - private boolean mTrackDragSort = false; - - /** - * Debugging class. - */ - private DragSortTracker mDragSortTracker; - - /** - * Needed for adjusting item heights from within layoutChildren - */ - private boolean mBlockLayoutRequests = false; - - /** - * Set to true when a down event happens during drag sort; - * for example, when drag finish animations are - * playing. - */ - private boolean mIgnoreTouchEvent = false; - - /** - * Caches DragSortItemView child heights. Sometimes DSLV has to - * know the height of an offscreen item. Since ListView virtualizes - * these, DSLV must get the item from the ListAdapter to obtain - * its height. That process can be expensive, but often the same - * offscreen item will be requested many times in a row. Once an - * offscreen item height is calculated, we cache it in this guy. - * Actually, we cache the height of the child of the - * DragSortItemView since the item height changes often during a - * drag-sort. - */ - private static final int sCacheSize = 3; - private HeightCache mChildHeightCache = new HeightCache(sCacheSize); - - private RemoveAnimator mRemoveAnimator; - - private LiftAnimator mLiftAnimator; - - private DropAnimator mDropAnimator; - - private boolean mUseRemoveVelocity; - private float mRemoveVelocityX = 0; - - public DragSortListView(Context context, AttributeSet attrs) { - super(context, attrs); - - int defaultDuration = 150; - int removeAnimDuration = defaultDuration; // ms - int dropAnimDuration = defaultDuration; // ms - - if (attrs != null) { - TypedArray a = getContext().obtainStyledAttributes(attrs, - R.styleable.DragSortListView, 0, 0); - - mItemHeightCollapsed = Math.max(1, a.getDimensionPixelSize( - R.styleable.DragSortListView_collapsedHeight, 1)); - - mTrackDragSort = a.getBoolean( - R.styleable.DragSortListView_trackDragSort, false); - - if (mTrackDragSort) { - mDragSortTracker = new DragSortTracker(); - } - - // alpha between 0 and 255, 0=transparent, 255=opaque - mFloatAlpha = a.getFloat(R.styleable.DragSortListView_floatAlpha, mFloatAlpha); - mCurrFloatAlpha = mFloatAlpha; - - mDragEnabled = a.getBoolean(R.styleable.DragSortListView_dragEnabled, mDragEnabled); - - mSlideRegionFrac = Math.max(0.0f, - Math.min(1.0f, 1.0f - a.getFloat( - R.styleable.DragSortListView_slideShuffleSpeed, - 0.75f))); - - mAnimate = mSlideRegionFrac > 0.0f; - - float frac = a.getFloat( - R.styleable.DragSortListView_dragScrollStart, - mDragUpScrollStartFrac); - - setDragScrollStart(frac); - - mMaxScrollSpeed = a.getFloat( - R.styleable.DragSortListView_maxDragScrollSpeed, - mMaxScrollSpeed); - - removeAnimDuration = a.getInt( - R.styleable.DragSortListView_removeAnimationDuration, - removeAnimDuration); - - dropAnimDuration = a.getInt( - R.styleable.DragSortListView_dropAnimationDuration, - dropAnimDuration); - - boolean useDefault = a.getBoolean( - R.styleable.DragSortListView_useDefaultController, - true); - - if (useDefault) { - boolean removeEnabled = a.getBoolean( - R.styleable.DragSortListView_removeEnabled, - false); - int removeMode = a.getInt( - R.styleable.DragSortListView_removeMode, - DragSortController.FLING_REMOVE); - boolean sortEnabled = a.getBoolean( - R.styleable.DragSortListView_sortEnabled, - true); - int dragInitMode = a.getInt( - R.styleable.DragSortListView_dragStartMode, - DragSortController.ON_DOWN); - int dragHandleId = a.getResourceId( - R.styleable.DragSortListView_dragHandleId, - 0); - int flingHandleId = a.getResourceId( - R.styleable.DragSortListView_flingHandleId, - 0); - int clickRemoveId = a.getResourceId( - R.styleable.DragSortListView_clickRemoveId, - 0); - int bgColor = a.getColor( - R.styleable.DragSortListView_floatBackgroundColor, - Color.BLACK); - - DragSortController controller = new DragSortController( - this, dragHandleId, dragInitMode, removeMode, - clickRemoveId, flingHandleId); - controller.setRemoveEnabled(removeEnabled); - controller.setSortEnabled(sortEnabled); - controller.setBackgroundColor(bgColor); - - mFloatViewManager = controller; - setOnTouchListener(controller); - } - - a.recycle(); - } - - mDragScroller = new DragScroller(); - - float smoothness = 0.5f; - if (removeAnimDuration > 0) { - mRemoveAnimator = new RemoveAnimator(smoothness, removeAnimDuration); - } - // mLiftAnimator = new LiftAnimator(smoothness, 100); - if (dropAnimDuration > 0) { - mDropAnimator = new DropAnimator(smoothness, dropAnimDuration); - } - - mCancelEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0f, 0f, 0, 0f, - 0f, 0, 0); - - // construct the dataset observer - mObserver = new DataSetObserver() { - private void cancel() { - if (mDragState == DRAGGING) { - cancelDrag(); - } - } - - @Override - public void onChanged() { - cancel(); - } - - @Override - public void onInvalidated() { - cancel(); - } - }; - } - - /** - * Usually called from a FloatViewManager. The float alpha - * will be reset to the xml-defined value every time a drag - * is stopped. - */ - public void setFloatAlpha(float alpha) { - mCurrFloatAlpha = alpha; - } - - public float getFloatAlpha() { - return mCurrFloatAlpha; - } - - /** - * Set maximum drag scroll speed in positions/second. Only applies - * if using default ScrollSpeedProfile. - * - * @param max Maximum scroll speed. - */ - public void setMaxScrollSpeed(float max) { - mMaxScrollSpeed = max; - } - - /** - * For each DragSortListView Listener interface implemented by - * adapter, this method calls the appropriate - * set*Listener method with adapter as the argument. - * - * @param adapter The ListAdapter providing data to back - * DragSortListView. - * - * @see android.widget.ListView#setAdapter(android.widget.ListAdapter) - */ - @Override - public void setAdapter(ListAdapter adapter) { - if (adapter != null) { - mAdapterWrapper = new AdapterWrapper(adapter); - adapter.registerDataSetObserver(mObserver); - - if (adapter instanceof DropListener) { - setDropListener((DropListener) adapter); - } - if (adapter instanceof DragListener) { - setDragListener((DragListener) adapter); - } - if (adapter instanceof RemoveListener) { - setRemoveListener((RemoveListener) adapter); - } - } else { - mAdapterWrapper = null; - } - - super.setAdapter(mAdapterWrapper); - } - - /** - * As opposed to {@link ListView#getAdapter()}, which returns - * a heavily wrapped ListAdapter (DragSortListView wraps the - * input ListAdapter {\emph and} ListView wraps the wrapped one). - * - * @return The ListAdapter set as the argument of {@link setAdapter()} - */ - public ListAdapter getInputAdapter() { - if (mAdapterWrapper == null) { - return null; - } else { - return mAdapterWrapper.getAdapter(); - } - } - - private class AdapterWrapper extends BaseAdapter { - private ListAdapter mAdapter; - - public AdapterWrapper(ListAdapter adapter) { - super(); - mAdapter = adapter; - - mAdapter.registerDataSetObserver(new DataSetObserver() { - public void onChanged() { - notifyDataSetChanged(); - } - - public void onInvalidated() { - notifyDataSetInvalidated(); - } - }); - } - - public ListAdapter getAdapter() { - return mAdapter; - } - - @Override - public long getItemId(int position) { - return mAdapter.getItemId(position); - } - - @Override - public Object getItem(int position) { - return mAdapter.getItem(position); - } - - @Override - public int getCount() { - return mAdapter.getCount(); - } - - @Override - public boolean areAllItemsEnabled() { - return mAdapter.areAllItemsEnabled(); - } - - @Override - public boolean isEnabled(int position) { - return mAdapter.isEnabled(position); - } - - @Override - public int getItemViewType(int position) { - return mAdapter.getItemViewType(position); - } - - @Override - public int getViewTypeCount() { - return mAdapter.getViewTypeCount(); - } - - @Override - public boolean hasStableIds() { - return mAdapter.hasStableIds(); - } - - @Override - public boolean isEmpty() { - return mAdapter.isEmpty(); - } - - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - - DragSortItemView v; - View child; - // Log.d("mobeta", - // "getView: position="+position+" convertView="+convertView); - if (convertView != null) { - v = (DragSortItemView) convertView; - View oldChild = v.getChildAt(0); - - child = mAdapter.getView(position, oldChild, DragSortListView.this); - if (child != oldChild) { - // shouldn't get here if user is reusing convertViews - // properly - if (oldChild != null) { - v.removeViewAt(0); - } - v.addView(child); - } - } else { - child = mAdapter.getView(position, null, DragSortListView.this); - v = new DragSortItemView(getContext()); - v.setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - v.addView(child); - } - - // Set the correct item height given drag state; passed - // View needs to be measured if measurement is required. - adjustItem(position + getHeaderViewsCount(), v, true); - - return v; - } - } - - private void drawDivider(int expPosition, Canvas canvas) { - - final Drawable divider = getDivider(); - final int dividerHeight = getDividerHeight(); - // Log.d("mobeta", "div="+divider+" divH="+dividerHeight); - - if (divider != null && dividerHeight != 0) { - final ViewGroup expItem = (ViewGroup) getChildAt(expPosition - - getFirstVisiblePosition()); - if (expItem != null) { - final int l = getPaddingLeft(); - final int r = getWidth() - getPaddingRight(); - final int t; - final int b; - - final int childHeight = expItem.getChildAt(0).getHeight(); - - if (expPosition > mSrcPos) { - t = expItem.getTop() + childHeight; - b = t + dividerHeight; - } else { - b = expItem.getBottom() - childHeight; - t = b - dividerHeight; - } - // Log.d("mobeta", "l="+l+" t="+t+" r="+r+" b="+b); - - // Have to clip to support ColorDrawable on <= Gingerbread - canvas.save(); - canvas.clipRect(l, t, r, b); - divider.setBounds(l, t, r, b); - divider.draw(canvas); - canvas.restore(); - } - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - - if (mDragState != IDLE) { - // draw the divider over the expanded item - if (mFirstExpPos != mSrcPos) { - drawDivider(mFirstExpPos, canvas); - } - if (mSecondExpPos != mFirstExpPos && mSecondExpPos != mSrcPos) { - drawDivider(mSecondExpPos, canvas); - } - } - - if (mFloatView != null) { - // draw the float view over everything - final int w = mFloatView.getWidth(); - final int h = mFloatView.getHeight(); - - int x = mFloatLoc.x; - - int width = getWidth(); - if (x < 0) - x = -x; - float alphaMod; - if (x < width) { - alphaMod = ((float) (width - x)) / ((float) width); - alphaMod *= alphaMod; - } else { - alphaMod = 0; - } - - final int alpha = (int) (255f * mCurrFloatAlpha * alphaMod); - - canvas.save(); - // Log.d("mobeta", "clip rect bounds: " + canvas.getClipBounds()); - canvas.translate(mFloatLoc.x, mFloatLoc.y); - canvas.clipRect(0, 0, w, h); - - // Log.d("mobeta", "clip rect bounds: " + canvas.getClipBounds()); - canvas.saveLayerAlpha(0, 0, w, h, alpha, Canvas.ALL_SAVE_FLAG); - mFloatView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - } - - private int getItemHeight(int position) { - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - // item is onscreen, just get the height of the View - return v.getHeight(); - } else { - // item is offscreen. get child height and calculate - // item height based on current shuffle state - return calcItemHeight(position, getChildHeight(position)); - } - } - - private void printPosData() { - Log.d("mobeta", "mSrcPos=" + mSrcPos + " mFirstExpPos=" + mFirstExpPos + " mSecondExpPos=" - + mSecondExpPos); - } - - private class HeightCache { - - private SparseIntArray mMap; - private ArrayList mOrder; - private int mMaxSize; - - public HeightCache(int size) { - mMap = new SparseIntArray(size); - mOrder = new ArrayList(size); - mMaxSize = size; - } - - /** - * Add item height at position if doesn't already exist. - */ - public void add(int position, int height) { - int currHeight = mMap.get(position, -1); - if (currHeight != height) { - if (currHeight == -1) { - if (mMap.size() == mMaxSize) { - // remove oldest entry - mMap.delete(mOrder.remove(0)); - } - } else { - // move position to newest slot - mOrder.remove((Integer) position); - } - mMap.put(position, height); - mOrder.add(position); - } - } - - public int get(int position) { - return mMap.get(position, -1); - } - - public void clear() { - mMap.clear(); - mOrder.clear(); - } - - } - - /** - * Get the shuffle edge for item at position when top of - * item is at y-coord top. Assumes that current item heights - * are consistent with current float view location and - * thus expanded positions and slide fraction. i.e. Should not be - * called between update of expanded positions/slide fraction - * and layoutChildren. - * - * @param position - * @param top - * @param height Height of item at position. If -1, this function - * calculates this height. - * - * @return Shuffle line between position-1 and position (for - * the given view of the list; that is, for when top of item at - * position has y-coord of given `top`). If - * floating View (treated as horizontal line) is dropped - * immediately above this line, it lands in position-1. If - * dropped immediately below this line, it lands in position. - */ - private int getShuffleEdge(int position, int top) { - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - // shuffle edges are defined between items that can be - // dragged; there are N-1 of them if there are N draggable - // items. - - if (position <= numHeaders || (position >= getCount() - numFooters)) { - return top; - } - - int divHeight = getDividerHeight(); - - int edge; - - int maxBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - int childHeight = getChildHeight(position); - int itemHeight = getItemHeight(position); - - // first calculate top of item given that floating View is - // centered over src position - int otop = top; - if (mSecondExpPos <= mSrcPos) { - // items are expanded on and/or above the source position - - if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - if (position == mSrcPos) { - otop = top + itemHeight - mFloatViewHeight; - } else { - int blankHeight = itemHeight - childHeight; - otop = top + blankHeight - maxBlankHeight; - } - } else if (position > mSecondExpPos && position <= mSrcPos) { - otop = top - maxBlankHeight; - } - - } else { - // items are expanded on and/or below the source position - - if (position > mSrcPos && position <= mFirstExpPos) { - otop = top + maxBlankHeight; - } else if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - int blankHeight = itemHeight - childHeight; - otop = top + blankHeight; - } - } - - // otop is set - if (position <= mSrcPos) { - edge = otop + (mFloatViewHeight - divHeight - getChildHeight(position - 1)) / 2; - } else { - edge = otop + (childHeight - divHeight - mFloatViewHeight) / 2; - } - - return edge; - } - - private boolean updatePositions() { - - final int first = getFirstVisiblePosition(); - int startPos = mFirstExpPos; - View startView = getChildAt(startPos - first); - - if (startView == null) { - startPos = first + getChildCount() / 2; - startView = getChildAt(startPos - first); - } - int startTop = startView.getTop(); - - int itemHeight = startView.getHeight(); - - int edge = getShuffleEdge(startPos, startTop); - int lastEdge = edge; - - int divHeight = getDividerHeight(); - - // Log.d("mobeta", "float mid="+mFloatViewMid); - - int itemPos = startPos; - int itemTop = startTop; - if (mFloatViewMid < edge) { - // scanning up for float position - // Log.d("mobeta", " edge="+edge); - while (itemPos >= 0) { - itemPos--; - itemHeight = getItemHeight(itemPos); - - if (itemPos == 0) { - edge = itemTop - divHeight - itemHeight; - break; - } - - itemTop -= itemHeight + divHeight; - edge = getShuffleEdge(itemPos, itemTop); - // Log.d("mobeta", " edge="+edge); - - if (mFloatViewMid >= edge) { - break; - } - - lastEdge = edge; - } - } else { - // scanning down for float position - // Log.d("mobeta", " edge="+edge); - final int count = getCount(); - while (itemPos < count) { - if (itemPos == count - 1) { - edge = itemTop + divHeight + itemHeight; - break; - } - - itemTop += divHeight + itemHeight; - itemHeight = getItemHeight(itemPos + 1); - edge = getShuffleEdge(itemPos + 1, itemTop); - // Log.d("mobeta", " edge="+edge); - - // test for hit - if (mFloatViewMid < edge) { - break; - } - - lastEdge = edge; - itemPos++; - } - } - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - boolean updated = false; - - int oldFirstExpPos = mFirstExpPos; - int oldSecondExpPos = mSecondExpPos; - float oldSlideFrac = mSlideFrac; - - if (mAnimate) { - int edgeToEdge = Math.abs(edge - lastEdge); - - int edgeTop, edgeBottom; - if (mFloatViewMid < edge) { - edgeBottom = edge; - edgeTop = lastEdge; - } else { - edgeTop = edge; - edgeBottom = lastEdge; - } - // Log.d("mobeta", "edgeTop="+edgeTop+" edgeBot="+edgeBottom); - - int slideRgnHeight = (int) (0.5f * mSlideRegionFrac * edgeToEdge); - float slideRgnHeightF = (float) slideRgnHeight; - int slideEdgeTop = edgeTop + slideRgnHeight; - int slideEdgeBottom = edgeBottom - slideRgnHeight; - - // Three regions - if (mFloatViewMid < slideEdgeTop) { - mFirstExpPos = itemPos - 1; - mSecondExpPos = itemPos; - mSlideFrac = 0.5f * ((float) (slideEdgeTop - mFloatViewMid)) / slideRgnHeightF; - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } else if (mFloatViewMid < slideEdgeBottom) { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos + 1; - mSlideFrac = 0.5f * (1.0f + ((float) (edgeBottom - mFloatViewMid)) - / slideRgnHeightF); - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } - - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - // correct for headers and footers - if (mFirstExpPos < numHeaders) { - itemPos = numHeaders; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else if (mSecondExpPos >= getCount() - numFooters) { - itemPos = getCount() - numFooters - 1; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - if (mFirstExpPos != oldFirstExpPos || mSecondExpPos != oldSecondExpPos - || mSlideFrac != oldSlideFrac) { - updated = true; - } - - if (itemPos != mFloatPos) { - if (mDragListener != null) { - mDragListener.drag(mFloatPos - numHeaders, itemPos - numHeaders); - } - - mFloatPos = itemPos; - updated = true; - } - - return updated; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (mTrackDragSort) { - mDragSortTracker.appendState(); - } - } - - private class SmoothAnimator implements Runnable { - protected long mStartTime; - - private float mDurationF; - - private float mAlpha; - private float mA, mB, mC, mD; - - private boolean mCanceled; - - public SmoothAnimator(float smoothness, int duration) { - mAlpha = smoothness; - mDurationF = (float) duration; - mA = mD = 1f / (2f * mAlpha * (1f - mAlpha)); - mB = mAlpha / (2f * (mAlpha - 1f)); - mC = 1f / (1f - mAlpha); - } - - public float transform(float frac) { - if (frac < mAlpha) { - return mA * frac * frac; - } else if (frac < 1f - mAlpha) { - return mB + mC * frac; - } else { - return 1f - mD * (frac - 1f) * (frac - 1f); - } - } - - public void start() { - mStartTime = SystemClock.uptimeMillis(); - mCanceled = false; - onStart(); - post(this); - } - - public void cancel() { - mCanceled = true; - } - - public void onStart() { - // stub - } - - public void onUpdate(float frac, float smoothFrac) { - // stub - } - - public void onStop() { - // stub - } - - @Override - public void run() { - if (mCanceled) { - return; - } - - float fraction = ((float) (SystemClock.uptimeMillis() - mStartTime)) / mDurationF; - - if (fraction >= 1f) { - onUpdate(1f, 1f); - onStop(); - } else { - onUpdate(fraction, transform(fraction)); - post(this); - } - } - } - - /** - * Centers floating View under touch point. - */ - private class LiftAnimator extends SmoothAnimator { - - private float mInitDragDeltaY; - private float mFinalDragDeltaY; - - public LiftAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mInitDragDeltaY = mDragDeltaY; - mFinalDragDeltaY = mFloatViewHeightHalf; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - if (mDragState != DRAGGING) { - cancel(); - } else { - mDragDeltaY = (int) (smoothFrac * mFinalDragDeltaY + (1f - smoothFrac) - * mInitDragDeltaY); - mFloatLoc.y = mY - mDragDeltaY; - doDragFloatView(true); - } - } - } - - /** - * Centers floating View over drop slot before destroying. - */ - private class DropAnimator extends SmoothAnimator { - - private int mDropPos; - private int srcPos; - private float mInitDeltaY; - private float mInitDeltaX; - - public DropAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mDropPos = mFloatPos; - srcPos = mSrcPos; - mDragState = DROPPING; - mInitDeltaY = mFloatLoc.y - getTargetY(); - mInitDeltaX = mFloatLoc.x - getPaddingLeft(); - } - - private int getTargetY() { - final int first = getFirstVisiblePosition(); - final int otherAdjust = (mItemHeightCollapsed + getDividerHeight()) / 2; - View v = getChildAt(mDropPos - first); - int targetY = -1; - if (v != null) { - if (mDropPos == srcPos) { - targetY = v.getTop(); - } else if (mDropPos < srcPos) { - // expanded down - targetY = v.getTop() - otherAdjust; - } else { - // expanded up - targetY = v.getBottom() + otherAdjust - mFloatViewHeight; - } - } else { - // drop position is not on screen?? no animation - cancel(); - } - - return targetY; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - final int targetY = getTargetY(); - final int targetX = getPaddingLeft(); - final float deltaY = mFloatLoc.y - targetY; - final float deltaX = mFloatLoc.x - targetX; - final float f = 1f - smoothFrac; - if (f < Math.abs(deltaY / mInitDeltaY) || f < Math.abs(deltaX / mInitDeltaX)) { - mFloatLoc.y = targetY + (int) (mInitDeltaY * f); - mFloatLoc.x = getPaddingLeft() + (int) (mInitDeltaX * f); - doDragFloatView(true); - } - } - - @Override - public void onStop() { - dropFloatView(); - } - - } - - /** - * Collapses expanded items. - */ - private class RemoveAnimator extends SmoothAnimator { - - private float mFloatLocX; - private float mFirstStartBlank; - private float mSecondStartBlank; - - private int mFirstChildHeight = -1; - private int mSecondChildHeight = -1; - - private int mFirstPos; - private int mSecondPos; - private int srcPos; - - public RemoveAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mFirstChildHeight = -1; - mSecondChildHeight = -1; - mFirstPos = mFirstExpPos; - mSecondPos = mSecondExpPos; - srcPos = mSrcPos; - mDragState = REMOVING; - - mFloatLocX = mFloatLoc.x; - if (mUseRemoveVelocity) { - float minVelocity = 2f * getWidth(); - if (mRemoveVelocityX == 0) { - mRemoveVelocityX = (mFloatLocX < 0 ? -1 : 1) * minVelocity; - } else { - minVelocity *= 2; - if (mRemoveVelocityX < 0 && mRemoveVelocityX > -minVelocity) - mRemoveVelocityX = -minVelocity; - else if (mRemoveVelocityX > 0 && mRemoveVelocityX < minVelocity) - mRemoveVelocityX = minVelocity; - } - } else { - destroyFloatView(); - } - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - float f = 1f - smoothFrac; - - final int firstVis = getFirstVisiblePosition(); - View item = getChildAt(mFirstPos - firstVis); - ViewGroup.LayoutParams lp; - int blank; - - if (mUseRemoveVelocity) { - float dt = (float) (SystemClock.uptimeMillis() - mStartTime) / 1000; - if (dt == 0) - return; - float dx = mRemoveVelocityX * dt; - int w = getWidth(); - mRemoveVelocityX += (mRemoveVelocityX > 0 ? 1 : -1) * dt * w; - mFloatLocX += dx; - mFloatLoc.x = (int) mFloatLocX; - if (mFloatLocX < w && mFloatLocX > -w) { - mStartTime = SystemClock.uptimeMillis(); - doDragFloatView(true); - return; - } - } - - if (item != null) { - if (mFirstChildHeight == -1) { - mFirstChildHeight = getChildHeight(mFirstPos, item, false); - mFirstStartBlank = (float) (item.getHeight() - mFirstChildHeight); - } - blank = Math.max((int) (f * mFirstStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mFirstChildHeight + blank; - item.setLayoutParams(lp); - } - if (mSecondPos != mFirstPos) { - item = getChildAt(mSecondPos - firstVis); - if (item != null) { - if (mSecondChildHeight == -1) { - mSecondChildHeight = getChildHeight(mSecondPos, item, false); - mSecondStartBlank = (float) (item.getHeight() - mSecondChildHeight); - } - blank = Math.max((int) (f * mSecondStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mSecondChildHeight + blank; - item.setLayoutParams(lp); - } - } - } - - @Override - public void onStop() { - doRemoveItem(); - } - } - - public void removeItem(int which) { - - mUseRemoveVelocity = false; - removeItem(which, 0); - } - - /** - * Removes an item from the list and animates the removal. - * - * @param which Position to remove (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). - * @param velocityX - */ - public void removeItem(int which, float velocityX) { - if (mDragState == IDLE || mDragState == DRAGGING) { - - if (mDragState == IDLE) { - // called from outside drag-sort - mSrcPos = getHeaderViewsCount() + which; - mFirstExpPos = mSrcPos; - mSecondExpPos = mSrcPos; - mFloatPos = mSrcPos; - View v = getChildAt(mSrcPos - getFirstVisiblePosition()); - if (v != null) { - v.setVisibility(View.INVISIBLE); - } - } - - mDragState = REMOVING; - mRemoveVelocityX = velocityX; - - if (mInTouchEvent) { - switch (mCancelMethod) { - case ON_TOUCH_EVENT: - super.onTouchEvent(mCancelEvent); - break; - case ON_INTERCEPT_TOUCH_EVENT: - super.onInterceptTouchEvent(mCancelEvent); - break; - } - } - - if (mRemoveAnimator != null) { - mRemoveAnimator.start(); - } else { - doRemoveItem(which); - } - } - } - - /** - * Move an item, bypassing the drag-sort process. Simply calls - * through to {@link DropListener#drop(int, int)}. - * - * @param from Position to move (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). - * @param to Target position (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). - */ - public void moveItem(int from, int to) { - if (mDropListener != null) { - final int count = getInputAdapter().getCount(); - if (from >= 0 && from < count && to >= 0 && to < count) { - mDropListener.drop(from, to); - } - } - } - - /** - * Cancel a drag. Calls {@link #stopDrag(boolean, boolean)} with - * true as the first argument. - */ - public void cancelDrag() { - if (mDragState == DRAGGING) { - mDragScroller.stopScrolling(true); - destroyFloatView(); - clearPositions(); - adjustAllItems(); - - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - } - - private void clearPositions() { - mSrcPos = -1; - mFirstExpPos = -1; - mSecondExpPos = -1; - mFloatPos = -1; - } - - private void dropFloatView() { - // must set to avoid cancelDrag being called from the - // DataSetObserver - mDragState = DROPPING; - - if (mDropListener != null && mFloatPos >= 0 && mFloatPos < getCount()) { - final int numHeaders = getHeaderViewsCount(); - mDropListener.drop(mSrcPos - numHeaders, mFloatPos - numHeaders); - } - - destroyFloatView(); - - adjustOnReorder(); - clearPositions(); - adjustAllItems(); - - // now the drag is done - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - - private void doRemoveItem() { - doRemoveItem(mSrcPos - getHeaderViewsCount()); - } - - /** - * Removes dragged item from the list. Calls RemoveListener. - */ - private void doRemoveItem(int which) { - // must set to avoid cancelDrag being called from the - // DataSetObserver - mDragState = REMOVING; - - // end it - if (mRemoveListener != null) { - mRemoveListener.remove(which); - } - - destroyFloatView(); - - adjustOnReorder(); - clearPositions(); - - // now the drag is done - if (mInTouchEvent) { - mDragState = STOPPED; - } else { - mDragState = IDLE; - } - } - - private void adjustOnReorder() { - final int firstPos = getFirstVisiblePosition(); - // Log.d("mobeta", "first="+firstPos+" src="+mSrcPos); - if (mSrcPos < firstPos) { - // collapsed src item is off screen; - // adjust the scroll after item heights have been fixed - View v = getChildAt(0); - int top = 0; - if (v != null) { - top = v.getTop(); - } - // Log.d("mobeta", "top="+top+" fvh="+mFloatViewHeight); - setSelectionFromTop(firstPos - 1, top - getPaddingTop()); - } - } - - /** - * Stop a drag in progress. Pass true if you would - * like to remove the dragged item from the list. - * - * @param remove Remove the dragged item from the list. Calls - * a registered RemoveListener, if one exists. Otherwise, calls - * the DropListener, if one exists. - * - * @return True if the stop was successful. False if there is - * no floating View. - */ - public boolean stopDrag(boolean remove) { - mUseRemoveVelocity = false; - return stopDrag(remove, 0); - } - - public boolean stopDragWithVelocity(boolean remove, float velocityX) { - - mUseRemoveVelocity = true; - return stopDrag(remove, velocityX); - } - - public boolean stopDrag(boolean remove, float velocityX) { - if (mFloatView != null) { - mDragScroller.stopScrolling(true); - - if (remove) { - removeItem(mSrcPos - getHeaderViewsCount(), velocityX); - } else { - if (mDropAnimator != null) { - mDropAnimator.start(); - } else { - dropFloatView(); - } - } - - if (mTrackDragSort) { - mDragSortTracker.stopTracking(); - } - - return true; - } else { - // stop failed - return false; - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mIgnoreTouchEvent) { - mIgnoreTouchEvent = false; - return false; - } - - if (!mDragEnabled) { - return super.onTouchEvent(ev); - } - - boolean more = false; - - boolean lastCallWasIntercept = mLastCallWasIntercept; - mLastCallWasIntercept = false; - - if (!lastCallWasIntercept) { - saveTouchCoords(ev); - } - - // if (mFloatView != null) { - if (mDragState == DRAGGING) { - onDragTouchEvent(ev); - more = true; // give us more! - } else { - // what if float view is null b/c we dropped in middle - // of drag touch event? - - // if (mDragState != STOPPED) { - if (mDragState == IDLE) { - if (super.onTouchEvent(ev)) { - more = true; - } - } - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (more) { - mCancelMethod = ON_TOUCH_EVENT; - } - } - } - - return more; - } - - private void doActionUpOrCancel() { - mCancelMethod = NO_CANCEL; - mInTouchEvent = false; - if (mDragState == STOPPED) { - mDragState = IDLE; - } - mCurrFloatAlpha = mFloatAlpha; - mListViewIntercepted = false; - mChildHeightCache.clear(); - } - - private void saveTouchCoords(MotionEvent ev) { - int action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action != MotionEvent.ACTION_DOWN) { - mLastX = mX; - mLastY = mY; - } - mX = (int) ev.getX(); - mY = (int) ev.getY(); - if (action == MotionEvent.ACTION_DOWN) { - mLastX = mX; - mLastY = mY; - } - mOffsetX = (int) ev.getRawX() - mX; - mOffsetY = (int) ev.getRawY() - mY; - } - - public boolean listViewIntercepted() { - return mListViewIntercepted; - } - - private boolean mListViewIntercepted = false; - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!mDragEnabled) { - return super.onInterceptTouchEvent(ev); - } - - saveTouchCoords(ev); - mLastCallWasIntercept = true; - - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - if (action == MotionEvent.ACTION_DOWN) { - if (mDragState != IDLE) { - // intercept and ignore - mIgnoreTouchEvent = true; - return true; - } - mInTouchEvent = true; - } - - boolean intercept = false; - - // the following deals with calls to super.onInterceptTouchEvent - if (mFloatView != null) { - // super's touch event canceled in startDrag - intercept = true; - } else { - if (super.onInterceptTouchEvent(ev)) { - mListViewIntercepted = true; - intercept = true; - } - - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (intercept) { - mCancelMethod = ON_TOUCH_EVENT; - } else { - mCancelMethod = ON_INTERCEPT_TOUCH_EVENT; - } - } - } - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mInTouchEvent = false; - } - - return intercept; - } - - /** - * Set the width of each drag scroll region by specifying - * a fraction of the ListView height. - * - * @param heightFraction Fraction of ListView height. Capped at - * 0.5f. - * - */ - public void setDragScrollStart(float heightFraction) { - setDragScrollStarts(heightFraction, heightFraction); - } - - /** - * Set the width of each drag scroll region by specifying - * a fraction of the ListView height. - * - * @param upperFrac Fraction of ListView height for up-scroll bound. - * Capped at 0.5f. - * @param lowerFrac Fraction of ListView height for down-scroll bound. - * Capped at 0.5f. - * - */ - public void setDragScrollStarts(float upperFrac, float lowerFrac) { - if (lowerFrac > 0.5f) { - mDragDownScrollStartFrac = 0.5f; - } else { - mDragDownScrollStartFrac = lowerFrac; - } - - if (upperFrac > 0.5f) { - mDragUpScrollStartFrac = 0.5f; - } else { - mDragUpScrollStartFrac = upperFrac; - } - - if (getHeight() != 0) { - updateScrollStarts(); - } - } - - private void continueDrag(int x, int y) { - - // proposed position - mFloatLoc.x = x - mDragDeltaX; - mFloatLoc.y = y - mDragDeltaY; - - doDragFloatView(true); - - int minY = Math.min(y, mFloatViewMid + mFloatViewHeightHalf); - int maxY = Math.max(y, mFloatViewMid - mFloatViewHeightHalf); - - // get the current scroll direction - int currentScrollDir = mDragScroller.getScrollDir(); - - if (minY > mLastY && minY > mDownScrollStartY && currentScrollDir != DragScroller.DOWN) { - // dragged down, it is below the down scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from up scroll to down scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling down - mDragScroller.startScrolling(DragScroller.DOWN); - } else if (maxY < mLastY && maxY < mUpScrollStartY && currentScrollDir != DragScroller.UP) { - // dragged up, it is above the up scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from down scroll to up scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling up - mDragScroller.startScrolling(DragScroller.UP); - } - else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY - && mDragScroller.isScrolling()) { - // not in the upper nor in the lower drag-scroll regions but it is - // still scrolling - - mDragScroller.stopScrolling(true); - } - } - - private void updateScrollStarts() { - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - float heightF = (float) listHeight; - - mUpScrollStartYF = padTop + mDragUpScrollStartFrac * heightF; - mDownScrollStartYF = padTop + (1.0f - mDragDownScrollStartFrac) * heightF; - - mUpScrollStartY = (int) mUpScrollStartYF; - mDownScrollStartY = (int) mDownScrollStartYF; - - mDragUpScrollHeight = mUpScrollStartYF - padTop; - mDragDownScrollHeight = padTop + listHeight - mDownScrollStartYF; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - updateScrollStarts(); - } - - private void adjustAllItems() { - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - - int begin = Math.max(0, getHeaderViewsCount() - first); - int end = Math.min(last - first, getCount() - 1 - getFooterViewsCount() - first); - - for (int i = begin; i <= end; ++i) { - View v = getChildAt(i); - if (v != null) { - adjustItem(first + i, v, false); - } - } - } - - private void adjustItem(int position) { - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - adjustItem(position, v, false); - } - } - - /** - * Sets layout param height, gravity, and visibility on - * wrapped item. - */ - private void adjustItem(int position, View v, boolean invalidChildHeight) { - - // Adjust item height - ViewGroup.LayoutParams lp = v.getLayoutParams(); - int height; - if (position != mSrcPos && position != mFirstExpPos && position != mSecondExpPos) { - height = ViewGroup.LayoutParams.WRAP_CONTENT; - } else { - height = calcItemHeight(position, v, invalidChildHeight); - } - - if (height != lp.height) { - lp.height = height; - v.setLayoutParams(lp); - } - - // Adjust item gravity - if (position == mFirstExpPos || position == mSecondExpPos) { - if (position < mSrcPos) { - ((DragSortItemView) v).setGravity(Gravity.BOTTOM); - } else if (position > mSrcPos) { - ((DragSortItemView) v).setGravity(Gravity.TOP); - } - } - - // Finally adjust item visibility - - int oldVis = v.getVisibility(); - int vis = View.VISIBLE; - - if (position == mSrcPos && mFloatView != null) { - vis = View.INVISIBLE; - } - - if (vis != oldVis) { - v.setVisibility(vis); - } - } - - private int getChildHeight(int position) { - if (position == mSrcPos) { - return 0; - } - - View v = getChildAt(position - getFirstVisiblePosition()); - - if (v != null) { - // item is onscreen, therefore child height is valid, - // hence the "true" - return getChildHeight(position, v, false); - } else { - // item is offscreen - // first check cache for child height at this position - int childHeight = mChildHeightCache.get(position); - if (childHeight != -1) { - // Log.d("mobeta", "found child height in cache!"); - return childHeight; - } - - final ListAdapter adapter = getAdapter(); - int type = adapter.getItemViewType(position); - - // There might be a better place for checking for the following - final int typeCount = adapter.getViewTypeCount(); - if (typeCount != mSampleViewTypes.length) { - mSampleViewTypes = new View[typeCount]; - } - - if (type >= 0) { - if (mSampleViewTypes[type] == null) { - v = adapter.getView(position, null, this); - mSampleViewTypes[type] = v; - } else { - v = adapter.getView(position, mSampleViewTypes[type], this); - } - } else { - // type is HEADER_OR_FOOTER or IGNORE - v = adapter.getView(position, null, this); - } - - // current child height is invalid, hence "true" below - childHeight = getChildHeight(position, v, true); - - // cache it because this could have been expensive - mChildHeightCache.add(position, childHeight); - - return childHeight; - } - } - - private int getChildHeight(int position, View item, boolean invalidChildHeight) { - if (position == mSrcPos) { - return 0; - } - - View child; - if (position < getHeaderViewsCount() || position >= getCount() - getFooterViewsCount()) { - child = item; - } else { - child = ((ViewGroup) item).getChildAt(0); - } - - ViewGroup.LayoutParams lp = child.getLayoutParams(); - - if (lp != null) { - if (lp.height > 0) { - return lp.height; - } - } - - int childHeight = child.getHeight(); - - if (childHeight == 0 || invalidChildHeight) { - measureItem(child); - childHeight = child.getMeasuredHeight(); - } - - return childHeight; - } - - private int calcItemHeight(int position, View item, boolean invalidChildHeight) { - return calcItemHeight(position, getChildHeight(position, item, invalidChildHeight)); - } - - private int calcItemHeight(int position, int childHeight) { - - int divHeight = getDividerHeight(); - - boolean isSliding = mAnimate && mFirstExpPos != mSecondExpPos; - int maxNonSrcBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - int slideHeight = (int) (mSlideFrac * maxNonSrcBlankHeight); - - int height; - - if (position == mSrcPos) { - if (mSrcPos == mFirstExpPos) { - if (isSliding) { - height = slideHeight + mItemHeightCollapsed; - } else { - height = mFloatViewHeight; - } - } else if (mSrcPos == mSecondExpPos) { - // if gets here, we know an item is sliding - height = mFloatViewHeight - slideHeight; - } else { - height = mItemHeightCollapsed; - } - } else if (position == mFirstExpPos) { - if (isSliding) { - height = childHeight + slideHeight; - } else { - height = childHeight + maxNonSrcBlankHeight; - } - } else if (position == mSecondExpPos) { - // we know an item is sliding (b/c 2ndPos != 1stPos) - height = childHeight + maxNonSrcBlankHeight - slideHeight; - } else { - height = childHeight; - } - - return height; - } - - @Override - public void requestLayout() { - if (!mBlockLayoutRequests) { - super.requestLayout(); - } - } - - private int adjustScroll(int movePos, View moveItem, int oldFirstExpPos, int oldSecondExpPos) { - int adjust = 0; - - final int childHeight = getChildHeight(movePos); - - int moveHeightBefore = moveItem.getHeight(); - int moveHeightAfter = calcItemHeight(movePos, childHeight); - - int moveBlankBefore = moveHeightBefore; - int moveBlankAfter = moveHeightAfter; - if (movePos != mSrcPos) { - moveBlankBefore -= childHeight; - moveBlankAfter -= childHeight; - } - - int maxBlank = mFloatViewHeight; - if (mSrcPos != mFirstExpPos && mSrcPos != mSecondExpPos) { - maxBlank -= mItemHeightCollapsed; - } - - if (movePos <= oldFirstExpPos) { - if (movePos > mFirstExpPos) { - adjust += maxBlank - moveBlankAfter; - } - } else if (movePos == oldSecondExpPos) { - if (movePos <= mFirstExpPos) { - adjust += moveBlankBefore - maxBlank; - } else if (movePos == mSecondExpPos) { - adjust += moveHeightBefore - moveHeightAfter; - } else { - adjust += moveBlankBefore; - } - } else { - if (movePos <= mFirstExpPos) { - adjust -= maxBlank; - } else if (movePos == mSecondExpPos) { - adjust -= moveBlankAfter; - } - } - - return adjust; - } - - private void measureItem(View item) { - ViewGroup.LayoutParams lp = item.getLayoutParams(); - if (lp == null) { - lp = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - item.setLayoutParams(lp); - } - int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getListPaddingLeft() - + getListPaddingRight(), lp.width); - int hspec; - if (lp.height > 0) { - hspec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); - } else { - hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - } - item.measure(wspec, hspec); - } - - private void measureFloatView() { - if (mFloatView != null) { - measureItem(mFloatView); - mFloatViewHeight = mFloatView.getMeasuredHeight(); - mFloatViewHeightHalf = mFloatViewHeight / 2; - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - // Log.d("mobeta", "onMeasure called"); - if (mFloatView != null) { - if (mFloatView.isLayoutRequested()) { - measureFloatView(); - } - mFloatViewOnMeasured = true; // set to false after layout - } - mWidthMeasureSpec = widthMeasureSpec; - } - - @Override - protected void layoutChildren() { - super.layoutChildren(); - - if (mFloatView != null) { - if (mFloatView.isLayoutRequested() && !mFloatViewOnMeasured) { - // Have to measure here when usual android measure - // pass is skipped. This happens during a drag-sort - // when layoutChildren is called directly. - measureFloatView(); - } - mFloatView.layout(0, 0, mFloatView.getMeasuredWidth(), mFloatView.getMeasuredHeight()); - mFloatViewOnMeasured = false; - } - } - - protected boolean onDragTouchEvent(MotionEvent ev) { - // we are in a drag - int action = ev.getAction() & MotionEvent.ACTION_MASK; - - switch (ev.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_CANCEL: - if (mDragState == DRAGGING) { - cancelDrag(); - } - doActionUpOrCancel(); - break; - case MotionEvent.ACTION_UP: - // Log.d("mobeta", "calling stopDrag from onDragTouchEvent"); - if (mDragState == DRAGGING) { - stopDrag(false); - } - doActionUpOrCancel(); - break; - case MotionEvent.ACTION_MOVE: - continueDrag((int) ev.getX(), (int) ev.getY()); - break; - } - - return true; - } - - private boolean mFloatViewInvalidated = false; - - private void invalidateFloatView() { - mFloatViewInvalidated = true; - } - - /** - * Start a drag of item at position using the - * registered FloatViewManager. Calls through - * to {@link #startDrag(int,View,int,int,int)} after obtaining - * the floating View from the FloatViewManager. - * - * @param position Item to drag. - * @param dragFlags Flags that restrict some movements of the - * floating View. For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating - * View in all directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the - * left edge of the floating View (i.e. touch-x minus float View - * left). - * @param deltaY Offset in y of the touch coordinate from the - * top edge of the floating View (i.e. touch-y minus float View - * top). - * - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in - * a touch event, there is no registered FloatViewManager, - * or the FloatViewManager returns a null View. - */ - public boolean startDrag(int position, int dragFlags, int deltaX, int deltaY) { - if (!mInTouchEvent || mFloatViewManager == null) { - return false; - } - - View v = mFloatViewManager.onCreateFloatView(position); - - if (v == null) { - return false; - } else { - return startDrag(position, v, dragFlags, deltaX, deltaY); - } - - } - - /** - * Start a drag of item at position without using - * a FloatViewManager. - * - * @param position Item to drag. - * @param floatView Floating View. - * @param dragFlags Flags that restrict some movements of the - * floating View. For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating - * View in all directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the - * left edge of the floating View (i.e. touch-x minus float View - * left). - * @param deltaY Offset in y of the touch coordinate from the - * top edge of the floating View (i.e. touch-y minus float View - * top). - * - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in - * a touch event, floatView is null, or there is - * a drag in progress. - */ - public boolean startDrag(int position, View floatView, int dragFlags, int deltaX, int deltaY) { - if (mDragState != IDLE || !mInTouchEvent || mFloatView != null || floatView == null - || !mDragEnabled) { - return false; - } - - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - - int pos = position + getHeaderViewsCount(); - mFirstExpPos = pos; - mSecondExpPos = pos; - mSrcPos = pos; - mFloatPos = pos; - - // mDragState = dragType; - mDragState = DRAGGING; - mDragFlags = 0; - mDragFlags |= dragFlags; - - mFloatView = floatView; - measureFloatView(); // sets mFloatViewHeight - - mDragDeltaX = deltaX; - mDragDeltaY = deltaY; - mDragStartY = mY; - - // updateFloatView(mX - mDragDeltaX, mY - mDragDeltaY); - mFloatLoc.x = mX - mDragDeltaX; - mFloatLoc.y = mY - mDragDeltaY; - - // set src item invisible - final View srcItem = getChildAt(mSrcPos - getFirstVisiblePosition()); - - if (srcItem != null) { - srcItem.setVisibility(View.INVISIBLE); - } - - if (mTrackDragSort) { - mDragSortTracker.startTracking(); - } - - // once float view is created, events are no longer passed - // to ListView - switch (mCancelMethod) { - case ON_TOUCH_EVENT: - super.onTouchEvent(mCancelEvent); - break; - case ON_INTERCEPT_TOUCH_EVENT: - super.onInterceptTouchEvent(mCancelEvent); - break; - } - - requestLayout(); - - if (mLiftAnimator != null) { - mLiftAnimator.start(); - } - - return true; - } - - private void doDragFloatView(boolean forceInvalidate) { - int movePos = getFirstVisiblePosition() + getChildCount() / 2; - View moveItem = getChildAt(getChildCount() / 2); - - if (moveItem == null) { - return; - } - - doDragFloatView(movePos, moveItem, forceInvalidate); - } - - private void doDragFloatView(int movePos, View moveItem, boolean forceInvalidate) { - mBlockLayoutRequests = true; - - updateFloatView(); - - int oldFirstExpPos = mFirstExpPos; - int oldSecondExpPos = mSecondExpPos; - - boolean updated = updatePositions(); - - if (updated) { - adjustAllItems(); - int scroll = adjustScroll(movePos, moveItem, oldFirstExpPos, oldSecondExpPos); - // Log.d("mobeta", " adjust scroll="+scroll); - - setSelectionFromTop(movePos, moveItem.getTop() + scroll - getPaddingTop()); - layoutChildren(); - } - - if (updated || forceInvalidate) { - invalidate(); - } - - mBlockLayoutRequests = false; - } - - /** - * Sets float View location based on suggested values and - * constraints set in mDragFlags. - */ - private void updateFloatView() { - - if (mFloatViewManager != null) { - mTouchLoc.set(mX, mY); - mFloatViewManager.onDragFloatView(mFloatView, mFloatLoc, mTouchLoc); - } - - final int floatX = mFloatLoc.x; - final int floatY = mFloatLoc.y; - - // restrict x motion - int padLeft = getPaddingLeft(); - if ((mDragFlags & DRAG_POS_X) == 0 && floatX > padLeft) { - mFloatLoc.x = padLeft; - } else if ((mDragFlags & DRAG_NEG_X) == 0 && floatX < padLeft) { - mFloatLoc.x = padLeft; - } - - // keep floating view from going past bottom of last header view - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - final int firstPos = getFirstVisiblePosition(); - final int lastPos = getLastVisiblePosition(); - - // Log.d("mobeta", - // "nHead="+numHeaders+" nFoot="+numFooters+" first="+firstPos+" last="+lastPos); - int topLimit = getPaddingTop(); - if (firstPos < numHeaders) { - topLimit = getChildAt(numHeaders - firstPos - 1).getBottom(); - } - if ((mDragFlags & DRAG_NEG_Y) == 0) { - if (firstPos <= mSrcPos) { - topLimit = Math.max(getChildAt(mSrcPos - firstPos).getTop(), topLimit); - } - } - // bottom limit is top of first footer View or - // bottom of last item in list - int bottomLimit = getHeight() - getPaddingBottom(); - if (lastPos >= getCount() - numFooters - 1) { - bottomLimit = getChildAt(getCount() - numFooters - 1 - firstPos).getBottom(); - } - if ((mDragFlags & DRAG_POS_Y) == 0) { - if (lastPos >= mSrcPos) { - bottomLimit = Math.min(getChildAt(mSrcPos - firstPos).getBottom(), bottomLimit); - } - } - - // Log.d("mobeta", "dragView top=" + (y - mDragDeltaY)); - // Log.d("mobeta", "limit=" + limit); - // Log.d("mobeta", "mDragDeltaY=" + mDragDeltaY); - - if (floatY < topLimit) { - mFloatLoc.y = topLimit; - } else if (floatY + mFloatViewHeight > bottomLimit) { - mFloatLoc.y = bottomLimit - mFloatViewHeight; - } - - // get y-midpoint of floating view (constrained to ListView bounds) - mFloatViewMid = mFloatLoc.y + mFloatViewHeightHalf; - } - - private void destroyFloatView() { - if (mFloatView != null) { - mFloatView.setVisibility(GONE); - if (mFloatViewManager != null) { - mFloatViewManager.onDestroyFloatView(mFloatView); - } - mFloatView = null; - invalidate(); - } - } - - /** - * Interface for customization of the floating View appearance - * and dragging behavior. Implement - * your own and pass it to {@link #setFloatViewManager}. If - * your own is not passed, the default {@link SimpleFloatViewManager} - * implementation is used. - */ - public interface FloatViewManager { - /** - * Return the floating View for item at position. - * DragSortListView will measure and layout this View for you, - * so feel free to just inflate it. You can help DSLV by - * setting some {@link ViewGroup.LayoutParams} on this View; - * otherwise it will set some for you (with a width of FILL_PARENT - * and a height of WRAP_CONTENT). - * - * @param position Position of item to drag (NOTE: - * position excludes header Views; thus, if you - * want to call {@link ListView#getChildAt(int)}, you will need - * to add {@link ListView#getHeaderViewsCount()} to the index). - * - * @return The View you wish to display as the floating View. - */ - public View onCreateFloatView(int position); - - /** - * Called whenever the floating View is dragged. Float View - * properties can be changed here. Also, the upcoming location - * of the float View can be altered by setting - * location.x and location.y. - * - * @param floatView The floating View. - * @param location The location (top-left; relative to DSLV - * top-left) at which the float - * View would like to appear, given the current touch location - * and the offset provided in {@link DragSortListView#startDrag}. - * @param touch The current touch location (relative to DSLV - * top-left). - * @param pendingScroll - */ - public void onDragFloatView(View floatView, Point location, Point touch); - - /** - * Called when the float View is dropped; lets you perform - * any necessary cleanup. The internal DSLV floating View - * reference is set to null immediately after this is called. - * - * @param floatView The floating View passed to - * {@link #onCreateFloatView(int)}. - */ - public void onDestroyFloatView(View floatView); - } - - public void setFloatViewManager(FloatViewManager manager) { - mFloatViewManager = manager; - } - - public void setDragListener(DragListener l) { - mDragListener = l; - } - - /** - * Allows for easy toggling between a DragSortListView - * and a regular old ListView. If enabled, items are - * draggable, where the drag init mode determines how - * items are lifted (see {@link setDragInitMode(int)}). - * If disabled, items cannot be dragged. - * - * @param enabled Set true to enable list - * item dragging - */ - public void setDragEnabled(boolean enabled) { - mDragEnabled = enabled; - } - - public boolean isDragEnabled() { - return mDragEnabled; - } - - /** - * This better reorder your ListAdapter! DragSortListView does not do this - * for you; doesn't make sense to. Make sure - * {@link BaseAdapter#notifyDataSetChanged()} or something like it is called - * in your implementation. Furthermore, if you have a choiceMode other than - * none and the ListAdapter does not return true for - * {@link ListAdapter#hasStableIds()}, you will need to call - * {@link #moveCheckState(int, int)} to move the check boxes along with the - * list items. - * - * @param l - */ - public void setDropListener(DropListener l) { - mDropListener = l; - } - - /** - * Probably a no-brainer, but make sure that your remove listener - * calls {@link BaseAdapter#notifyDataSetChanged()} or something like it. - * When an item removal occurs, DragSortListView - * relies on a redraw of all the items to recover invisible views - * and such. Strictly speaking, if you remove something, your dataset - * has changed... - * - * @param l - */ - public void setRemoveListener(RemoveListener l) { - mRemoveListener = l; - } - - public interface DragListener { - public void drag(int from, int to); - } - - /** - * Your implementation of this has to reorder your ListAdapter! - * Make sure to call - * {@link BaseAdapter#notifyDataSetChanged()} or something like it - * in your implementation. - * - * @author heycosmo - * - */ - public interface DropListener { - public void drop(int from, int to); - } - - /** - * Make sure to call - * {@link BaseAdapter#notifyDataSetChanged()} or something like it - * in your implementation. - * - * @author heycosmo - * - */ - public interface RemoveListener { - public void remove(int which); - } - - public interface DragSortListener extends DropListener, DragListener, RemoveListener { - } - - public void setDragSortListener(DragSortListener l) { - setDropListener(l); - setDragListener(l); - setRemoveListener(l); - } - - /** - * Completely custom scroll speed profile. Default increases linearly - * with position and is constant in time. Create your own by implementing - * {@link DragSortListView.DragScrollProfile}. - * - * @param ssp - */ - public void setDragScrollProfile(DragScrollProfile ssp) { - if (ssp != null) { - mScrollProfile = ssp; - } - } - - /** - * Use this to move the check state of an item from one position to another - * in a drop operation. If you have a choiceMode which is not none, this - * method must be called when the order of items changes in an underlying - * adapter which does not have stable IDs (see - * {@link ListAdapter#hasStableIds()}). This is because without IDs, the - * ListView has no way of knowing which items have moved where, and cannot - * update the check state accordingly. - *

- * A word of warning about a "feature" in Android that you may run into when - * dealing with movable list items: for an adapter that does have - * stable IDs, ListView will attempt to locate each item based on its ID and - * move the check state from the item's old position to the new position — - * which is all fine and good (and removes the need for calling this - * function), except for the half-baked approach. Apparently to save time in - * the naive algorithm used, ListView will only search for an ID in the - * close neighborhood of the old position. If the user moves an item too far - * (specifically, more than 20 rows away), ListView will give up and just - * force the item to be unchecked. So if there is a reasonable chance that - * the user will move items more than 20 rows away from the original - * position, you may wish to use an adapter with unstable IDs and call this - * method manually instead. - * - * @param from - * @param to - */ - public void moveCheckState(int from, int to) { - // This method runs in O(n log n) time (n being the number of list - // items). The bottleneck is the call to AbsListView.setItemChecked, - // which is O(log n) because of the binary search involved in calling - // SparseBooleanArray.put(). - // - // To improve on the average time, we minimize the number of calls to - // setItemChecked by only calling it for items that actually have a - // changed state. This is achieved by building a list containing the - // start and end of the "runs" of checked items, and then moving the - // runs. Note that moving an item from A to B is essentially a rotation - // of the range of items in [A, B]. Let's say we have - // . . U V X Y Z . . - // and move U after Z. This is equivalent to a rotation one step to the - // left within the range you are moving across: - // . . V X Y Z U . . - // - // So, to perform the move we enumerate all the runs within the move - // range, then rotate each run one step to the left or right (depending - // on move direction). For example, in the list: - // X X . X X X . X - // we have two runs. One begins at the last item of the list and wraps - // around to the beginning, ending at position 1. The second begins at - // position 3 and ends at position 5. To rotate a run, regardless of - // length, we only need to set a check mark at one end of the run, and - // clear a check mark at the other end: - // X . X X X . X X - SparseBooleanArray cip = getCheckedItemPositions(); - int rangeStart = from; - int rangeEnd = to; - if (to < from) { - rangeStart = to; - rangeEnd = from; - } - rangeEnd += 1; - - int[] runStart = new int[cip.size()]; - int[] runEnd = new int[cip.size()]; - int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd); - if (runCount == 1 && (runStart[0] == runEnd[0])) { - // Special case where all items are checked, we can never set any - // item to false like we do below. - return; - } - - if (from < to) { - for (int i = 0; i != runCount; i++) { - setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true); - setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false); - } - - } else { - for (int i = 0; i != runCount; i++) { - setItemChecked(runStart[i], false); - setItemChecked(runEnd[i], true); - } - } - } - - /** - * Use this when an item has been deleted, to move the check state of all - * following items up one step. If you have a choiceMode which is not none, - * this method must be called when the order of items changes in an - * underlying adapter which does not have stable IDs (see - * {@link ListAdapter#hasStableIds()}). This is because without IDs, the - * ListView has no way of knowing which items have moved where, and cannot - * update the check state accordingly. - * - * See also further comments on {@link #moveCheckState(int, int)}. - * - * @param position - */ - public void removeCheckState(int position) { - SparseBooleanArray cip = getCheckedItemPositions(); - - if (cip.size() == 0) - return; - int[] runStart = new int[cip.size()]; - int[] runEnd = new int[cip.size()]; - int rangeStart = position; - int rangeEnd = cip.keyAt(cip.size() - 1) + 1; - int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd); - for (int i = 0; i != runCount; i++) { - if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) { - // Only set a new check mark in front of this run if it does - // not contain the deleted position. If it does, we only need - // to make it one check mark shorter at the end. - setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true); - } - setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false); - } - } - - private static int buildRunList(SparseBooleanArray cip, int rangeStart, - int rangeEnd, int[] runStart, int[] runEnd) { - int runCount = 0; - - int i = findFirstSetIndex(cip, rangeStart, rangeEnd); - if (i == -1) - return 0; - - int position = cip.keyAt(i); - int currentRunStart = position; - int currentRunEnd = currentRunStart + 1; - for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) { - if (!cip.valueAt(i)) // not checked => not interesting - continue; - if (position == currentRunEnd) { - currentRunEnd++; - } else { - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - currentRunStart = position; - currentRunEnd = position + 1; - } - } - - if (currentRunEnd == rangeEnd) { - // rangeStart and rangeEnd are equivalent positions so to be - // consistent we translate them to the same integer value. That way - // we can check whether a run covers the entire range by just - // checking if the start equals the end position. - currentRunEnd = rangeStart; - } - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - - if (runCount > 1) { - if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) { - // The last run ends at the end of the range, and the first run - // starts at the beginning of the range. So they are actually - // part of the same run, except they wrap around the end of the - // range. To avoid adjacent runs, we need to merge them. - runStart[0] = runStart[runCount - 1]; - runCount--; - } - } - return runCount; - } - - private static int rotate(int value, int offset, int lowerBound, int upperBound) { - int windowSize = upperBound - lowerBound; - - value += offset; - if (value < lowerBound) { - value += windowSize; - } else if (value >= upperBound) { - value -= windowSize; - } - return value; - } - - private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) { - int size = sba.size(); - int i = insertionIndexForKey(sba, rangeStart); - while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i)) - i++; - if (i == size || sba.keyAt(i) >= rangeEnd) - return -1; - return i; - } - - private static int insertionIndexForKey(SparseBooleanArray sba, int key) { - int low = 0; - int high = sba.size(); - while (high - low > 0) { - int middle = (low + high) >> 1; - if (sba.keyAt(middle) < key) - low = middle + 1; - else - high = middle; - } - return low; - } - - /** - * Interface for controlling - * scroll speed as a function of touch position and time. Use - * {@link DragSortListView#setDragScrollProfile(DragScrollProfile)} to - * set custom profile. - * - * @author heycosmo - * - */ - public interface DragScrollProfile { - /** - * Return a scroll speed in pixels/millisecond. Always return a - * positive number. - * - * @param w Normalized position in scroll region (i.e. w \in [0,1]). - * Small w typically means slow scrolling. - * @param t Time (in milliseconds) since start of scroll (handy if you - * want scroll acceleration). - * @return Scroll speed at position w and time t in pixels/ms. - */ - float getSpeed(float w, long t); - } - - private class DragScroller implements Runnable { - - private boolean mAbort; - - private long mPrevTime; - private long mCurrTime; - - private int dy; - private float dt; - private long tStart; - private int scrollDir; - - public final static int STOP = -1; - public final static int UP = 0; - public final static int DOWN = 1; - - private float mScrollSpeed; // pixels per ms - - private boolean mScrolling = false; - - private int mLastHeader; - private int mFirstFooter; - - public boolean isScrolling() { - return mScrolling; - } - - public int getScrollDir() { - return mScrolling ? scrollDir : STOP; - } - - public DragScroller() { - } - - public void startScrolling(int dir) { - if (!mScrolling) { - // Debug.startMethodTracing("dslv-scroll"); - mAbort = false; - mScrolling = true; - tStart = SystemClock.uptimeMillis(); - mPrevTime = tStart; - scrollDir = dir; - post(this); - } - } - - public void stopScrolling(boolean now) { - if (now) { - DragSortListView.this.removeCallbacks(this); - mScrolling = false; - } else { - mAbort = true; - } - - // Debug.stopMethodTracing(); - } - - @Override - public void run() { - if (mAbort) { - mScrolling = false; - return; - } - - // Log.d("mobeta", "scroll"); - - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - final int count = getCount(); - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - - int minY = Math.min(mY, mFloatViewMid + mFloatViewHeightHalf); - int maxY = Math.max(mY, mFloatViewMid - mFloatViewHeightHalf); - - if (scrollDir == UP) { - View v = getChildAt(0); - // Log.d("mobeta", "vtop="+v.getTop()+" padtop="+padTop); - if (v == null) { - mScrolling = false; - return; - } else { - if (first == 0 && v.getTop() == padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = mScrollProfile.getSpeed((mUpScrollStartYF - maxY) - / mDragUpScrollHeight, mPrevTime); - } else { - View v = getChildAt(last - first); - if (v == null) { - mScrolling = false; - return; - } else { - if (last == count - 1 && v.getBottom() <= listHeight + padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = -mScrollProfile.getSpeed((minY - mDownScrollStartYF) - / mDragDownScrollHeight, mPrevTime); - } - - mCurrTime = SystemClock.uptimeMillis(); - dt = (float) (mCurrTime - mPrevTime); - - // dy is change in View position of a list item; i.e. positive dy - // means user is scrolling up (list item moves down the screen, - // remember - // y=0 is at top of View). - dy = (int) Math.round(mScrollSpeed * dt); - - int movePos; - if (dy >= 0) { - dy = Math.min(listHeight, dy); - movePos = first; - } else { - dy = Math.max(-listHeight, dy); - movePos = last; - } - - final View moveItem = getChildAt(movePos - first); - int top = moveItem.getTop() + dy; - - if (movePos == 0 && top > padTop) { - top = padTop; - } - - // always do scroll - mBlockLayoutRequests = true; - - setSelectionFromTop(movePos, top - padTop); - DragSortListView.this.layoutChildren(); - invalidate(); - - mBlockLayoutRequests = false; - - // scroll means relative float View movement - doDragFloatView(movePos, moveItem, false); - - mPrevTime = mCurrTime; - // Log.d("mobeta", " updated prevTime="+mPrevTime); - - post(this); - } - } - - private class DragSortTracker { - StringBuilder mBuilder = new StringBuilder(); - - File mFile; - - private int mNumInBuffer = 0; - private int mNumFlushes = 0; - - private boolean mTracking = false; - - public DragSortTracker() { - File root = Environment.getExternalStorageDirectory(); - mFile = new File(root, "dslv_state.txt"); - - if (!mFile.exists()) { - try { - mFile.createNewFile(); - Log.d("mobeta", "file created"); - } catch (IOException e) { - Log.w("mobeta", "Could not create dslv_state.txt"); - Log.d("mobeta", e.getMessage()); - } - } - - } - - public void startTracking() { - mBuilder.append("\n"); - mNumFlushes = 0; - mTracking = true; - } - - public void appendState() { - if (!mTracking) { - return; - } - - mBuilder.append("\n"); - final int children = getChildCount(); - final int first = getFirstVisiblePosition(); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(first + i).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getTop()).append(","); - } - mBuilder.append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getBottom()).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" ").append(mFirstExpPos).append("\n"); - mBuilder.append(" ") - .append(getItemHeight(mFirstExpPos) - getChildHeight(mFirstExpPos)) - .append("\n"); - mBuilder.append(" ").append(mSecondExpPos).append("\n"); - mBuilder.append(" ") - .append(getItemHeight(mSecondExpPos) - getChildHeight(mSecondExpPos)) - .append("\n"); - mBuilder.append(" ").append(mSrcPos).append("\n"); - mBuilder.append(" ").append(mFloatViewHeight + getDividerHeight()) - .append("\n"); - mBuilder.append(" ").append(getHeight()).append("\n"); - mBuilder.append(" ").append(mLastY).append("\n"); - mBuilder.append(" ").append(mFloatViewMid).append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getShuffleEdge(first + i, getChildAt(i).getTop())).append(","); - } - mBuilder.append("\n"); - - mBuilder.append("\n"); - mNumInBuffer++; - - if (mNumInBuffer > 1000) { - flush(); - mNumInBuffer = 0; - } - } - - public void flush() { - if (!mTracking) { - return; - } - - // save to file on sdcard - try { - boolean append = true; - if (mNumFlushes == 0) { - append = false; - } - FileWriter writer = new FileWriter(mFile, append); - - writer.write(mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - - writer.flush(); - writer.close(); - - mNumFlushes++; - } catch (IOException e) { - // do nothing - } - } - - public void stopTracking() { - if (mTracking) { - mBuilder.append("\n"); - flush(); - mTracking = false; - } - } - - } - -} diff --git a/src/com/cherish/settings/preferences/dslv/SimpleFloatViewManager.java b/src/com/cherish/settings/preferences/dslv/SimpleFloatViewManager.java deleted file mode 100644 index 502b9f2..0000000 --- a/src/com/cherish/settings/preferences/dslv/SimpleFloatViewManager.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2012 Carl Bauer - * Copyright (C) 2014 SlimRoms 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.cherish.settings.preferences.dslv; - -import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Color; -import android.widget.ListView; -import android.widget.ImageView; -import android.view.View; -import android.view.ViewGroup; -import android.util.Log; - -/** - * Simple implementation of the FloatViewManager class. Uses list - * items as they appear in the ListView to create the floating View. - */ -public class SimpleFloatViewManager implements DragSortListView.FloatViewManager { - - private Bitmap mFloatBitmap; - - private ImageView mImageView; - - private int mFloatBGColor = Color.BLACK; - - private ListView mListView; - - public SimpleFloatViewManager(ListView lv) { - mListView = lv; - } - - public void setBackgroundColor(int color) { - mFloatBGColor = color; - } - - /** - * This simple implementation creates a Bitmap copy of the - * list item currently shown at ListView position. - */ - @Override - public View onCreateFloatView(int position) { - // Guaranteed that this will not be null? I think so. Nope, got - // a NullPointerException once... - View v = mListView.getChildAt( - position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition()); - - if (v == null) { - return null; - } - - v.setPressed(false); - - // Create a copy of the drawing cache so that it does not get - // recycled by the framework when the list tries to clean up memory - //v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); - v.setDrawingCacheEnabled(true); - mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache()); - v.setDrawingCacheEnabled(false); - - if (mImageView == null) { - mImageView = new ImageView(mListView.getContext()); - } - mImageView.setBackgroundColor(mFloatBGColor); - mImageView.setPadding(0, 0, 0, 0); - mImageView.setImageBitmap(mFloatBitmap); - mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight())); - - return mImageView; - } - - /** - * This does nothing - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - // do nothing - } - - /** - * Removes the Bitmap from the ImageView created in - * onCreateFloatView() and tells the system to recycle it. - */ - @Override - public void onDestroyFloatView(View floatView) { - ((ImageView) floatView).setImageDrawable(null); - - mFloatBitmap.recycle(); - mFloatBitmap = null; - } - -}