diff options
-rw-r--r-- | AndroidManifest.xml | 13 | ||||
-rw-r--r-- | res/anim/button_elevation.xml | 51 | ||||
-rw-r--r-- | res/drawable/fab_accent.xml | 27 | ||||
-rw-r--r-- | res/drawable/floating_action_button.xml | 34 | ||||
-rw-r--r-- | res/layout-sw600dp/suggestion_item.xml | 2 | ||||
-rw-r--r-- | res/layout/new_folder_layout.xml | 48 | ||||
-rw-r--r-- | res/layout/qc_menu_item.xml | 2 | ||||
-rw-r--r-- | res/layout/suggestion_item.xml | 2 | ||||
-rw-r--r-- | res/layout/tab_title.xml | 2 | ||||
-rw-r--r-- | res/values-sw600dp/styles.xml | 8 | ||||
-rw-r--r-- | res/values/dimensions.xml | 1 | ||||
-rw-r--r-- | res/values/styles.xml | 6 | ||||
-rw-r--r-- | src/com/android/browser/NavScreen.java | 64 | ||||
-rw-r--r-- | src/com/android/browser/NavTabScroller.java | 1066 |
14 files changed, 665 insertions, 661 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c85ed3b..ce6ba36 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -148,7 +148,7 @@ </activity> <activity android:name="ShortcutActivity" - android:theme="@style/PreferencesTheme" + android:theme="@style/PreferencesTheme" android:label="@string/shortcut_bookmark" android:icon="@mipmap/ic_launcher_shortcut_browser_bookmark"> <intent-filter> @@ -158,7 +158,9 @@ </activity> - <activity android:name="BrowserPreferencesPage" android:label="@string/menu_preferences" android:theme="@style/PreferencesTheme"> + <activity android:name="BrowserPreferencesPage" + android:label="@string/menu_preferences" + android:theme="@style/PreferencesTheme"> <intent-filter> <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> <category android:name="android.intent.category.DEFAULT" /> @@ -178,7 +180,8 @@ android:resource="@xml/bookmarks_searchable" /> </activity> - <activity android:name="AddBookmarkPage" android:label="@string/bookmarks_add_page" + <activity android:name="AddBookmarkPage" + android:label="@string/bookmarks_add_page" android:theme="@style/PreferencesTheme" android:configChanges="orientation|keyboardHidden|screenSize" android:windowSoftInputMode="adjustResize"> @@ -186,11 +189,11 @@ <action android:name="android.intent.action.INSERT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.dir/bookmark"/> - android:theme="@style/PreferencesTheme" </intent-filter> + </intent-filter> </activity> <activity android:name="ComboViewActivity" - android:theme="@style/PreferencesTheme"> + android:theme="@style/PreferencesTheme"> </activity> <!-- Bookmark thumbnail homescreen widget --> diff --git a/res/anim/button_elevation.xml b/res/anim/button_elevation.xml index 9159646..21dd654 100644 --- a/res/anim/button_elevation.xml +++ b/res/anim/button_elevation.xml @@ -1,33 +1,34 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The CyanogenMod Project +<!-- + Copyright (C) 2014 The CyanogenMod 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 + 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 + 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. + 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. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true"> - <objectAnimator - android:propertyName="translationZ" - android:duration="@android:integer/config_shortAnimTime" - android:valueFrom="@dimen/elevation_low" - android:valueTo="@dimen/elevation_high" - android:valueType="floatType"/> + <item android:state_pressed="true"> + <objectAnimator + android:propertyName="translationZ" + android:duration="@android:integer/config_shortAnimTime" + android:valueFrom="@dimen/elevation_low" + android:valueTo="@dimen/elevation_high" + android:valueType="floatType"/> </item> <item> - <objectAnimator - android:propertyName="translationZ" - android:duration="@android:integer/config_shortAnimTime" - android:valueFrom="@dimen/elevation_high" - android:valueTo="@dimen/elevation_low" - android:valueType="floatType"/> - </item> - </selector> + <objectAnimator + android:propertyName="translationZ" + android:duration="@android:integer/config_shortAnimTime" + android:valueFrom="@dimen/elevation_high" + android:valueTo="@dimen/elevation_low" + android:valueType="floatType"/> + </item> +</selector> diff --git a/res/drawable/fab_accent.xml b/res/drawable/fab_accent.xml index fabd583..01aa084 100644 --- a/res/drawable/fab_accent.xml +++ b/res/drawable/fab_accent.xml @@ -1,19 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The CyanogenMod Project +<!-- + Copyright (C) 2014 The CyanogenMod 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 + 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 + 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. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. --> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> - <solid android:color="@color/primary" /> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid android:color="@color/primary" /> </shape> diff --git a/res/drawable/floating_action_button.xml b/res/drawable/floating_action_button.xml index 0f313cb..ef95367 100644 --- a/res/drawable/floating_action_button.xml +++ b/res/drawable/floating_action_button.xml @@ -1,24 +1,24 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The CyanogenMod Project +<!-- + Copyright (C) 2014 The CyanogenMod 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 + 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 + 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. + 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. --> - <ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/floating_action_button_touch_tint"> - <item android:id="@android:id/mask"> - <shape android:shape="oval"> - <solid android:color="@color/primary" /> - </shape> - </item> + android:color="@color/floating_action_button_touch_tint"> + <item android:id="@android:id/mask"> + <shape android:shape="oval"> + <solid android:color="@color/primary" /> + </shape> + </item> </ripple> diff --git a/res/layout-sw600dp/suggestion_item.xml b/res/layout-sw600dp/suggestion_item.xml index 020ba58..b1a809b 100644 --- a/res/layout-sw600dp/suggestion_item.xml +++ b/res/layout-sw600dp/suggestion_item.xml @@ -81,5 +81,5 @@ android:background="?android:attr/selectableItemBackground" android:paddingRight="@dimen/suggest_item_padding" android:paddingLeft="@dimen/suggest_item_padding" - /> + /> </LinearLayout> diff --git a/res/layout/new_folder_layout.xml b/res/layout/new_folder_layout.xml index 7db5b38..76cc2f2 100644 --- a/res/layout/new_folder_layout.xml +++ b/res/layout/new_folder_layout.xml @@ -27,30 +27,30 @@ android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeight" android:src="@drawable/ic_folder_dark" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="@*android:drawable/edit_text_holo_dark" - android:gravity="center_vertical" - android:paddingBottom="5dip" - android:orientation="horizontal"> - <EditText - android:id="@+id/folder_namer" - android:layout_width="0dip" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:textAppearance="?android:attr/textAppearanceMedium" - android:background="@null" + android:background="@*android:drawable/edit_text_holo_dark" android:gravity="center_vertical" - android:paddingLeft="6dip" - /> - <ImageView - android:id="@+id/close" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_vertical" - android:src="@drawable/ic_tab_close" - android:contentDescription="@string/cancel" - /> - </LinearLayout> + android:paddingBottom="5dip" + android:orientation="horizontal"> + <EditText + android:id="@+id/folder_namer" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceMedium" + android:background="@null" + android:gravity="center_vertical" + android:paddingLeft="6dip" + /> + <ImageView + android:id="@+id/close" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:src="@drawable/ic_tab_close" + android:contentDescription="@string/cancel" + /> + </LinearLayout> </LinearLayout> diff --git a/res/layout/qc_menu_item.xml b/res/layout/qc_menu_item.xml index 99c1eb9..ae05362 100644 --- a/res/layout/qc_menu_item.xml +++ b/res/layout/qc_menu_item.xml @@ -28,4 +28,4 @@ android:paddingTop="4dip" android:paddingBottom="4dip" android:elevation="8dp" - /> + /> diff --git a/res/layout/suggestion_item.xml b/res/layout/suggestion_item.xml index 0adea1b..9a08517 100644 --- a/res/layout/suggestion_item.xml +++ b/res/layout/suggestion_item.xml @@ -77,5 +77,5 @@ android:background="?android:attr/selectableItemBackground" android:paddingRight="@dimen/suggest_item_padding" android:paddingLeft="@dimen/suggest_item_padding" - /> + /> </LinearLayout> diff --git a/res/layout/tab_title.xml b/res/layout/tab_title.xml index 3f72753..954ffa3 100644 --- a/res/layout/tab_title.xml +++ b/res/layout/tab_title.xml @@ -31,7 +31,7 @@ android:layout_height="match_parent" android:gravity="center_vertical" android:src="@drawable/ic_search_category_history" - android:contentDescription="@string/accessibility_state_frozen" + android:contentDescription="@string/accessibility_state_frozen" android:visibility="gone" /> <ImageView android:id="@+id/favicon" diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml index f03cac1..20e42f4 100644 --- a/res/values-sw600dp/styles.xml +++ b/res/values-sw600dp/styles.xml @@ -28,11 +28,11 @@ <item name="android:actionBarSize">64dip</item> </style> <style name="Suggestions" parent="@android:style/Widget.Material.Light.AutoCompleteTextView"> - <item name="android:textColor">@color/white</item> - <item name="android:textColorHint">@color/white</item> - <item name="android:dropDownVerticalOffset">0dip</item> + <item name="android:textColor">@color/white</item> + <item name="android:textColorHint">@color/white</item> + <item name="android:dropDownVerticalOffset">0dip</item> </style> <style name="ActionBarStyle" parent="@android:style/ThemeOverlay.Material.Dark.ActionBar"> <item name="android:background">@color/primary</item> - </style> + </style> </resources> diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml index 019a173..b285344 100644 --- a/res/values/dimensions.xml +++ b/res/values/dimensions.xml @@ -78,5 +78,4 @@ <dimen name="elevation_low">1dp</dimen> <dimen name="elevation_high">4dp</dimen> <dimen name="add_button_margin">16dp</dimen> - </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index 7e3c30a..0ad7ffe 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -30,9 +30,9 @@ <item name="android:colorAccent">@color/accent</item> </style> <style name="PreferencesTheme" parent="@android:Theme.Material.Light.DarkActionBar"> - <item name="android:colorPrimary">@color/primary</item> - <item name="android:colorPrimaryDark">@color/primary_dark</item> - <item name="android:colorAccent">@color/accent</item> + <item name="android:colorPrimary">@color/primary</item> + <item name="android:colorPrimaryDark">@color/primary_dark</item> + <item name="android:colorAccent">@color/accent</item> </style> <style name="DialogWhenLarge" parent="@android:style/Theme.Material.DialogWhenLarge" > <item name="android:windowActionBar">false</item> diff --git a/src/com/android/browser/NavScreen.java b/src/com/android/browser/NavScreen.java index 7730cae..85eaa41 100644 --- a/src/com/android/browser/NavScreen.java +++ b/src/com/android/browser/NavScreen.java @@ -114,38 +114,38 @@ public class NavScreen extends RelativeLayout } private void init() { - LayoutInflater.from(mContext).inflate(R.layout.nav_screen, this); - setContentDescription(mContext.getResources().getString( - R.string.accessibility_transition_navscreen)); - mBookmarks = (ImageButton) findViewById(R.id.bookmarks); - mNewTab = (ImageButton) findViewById(R.id.newtab); - mMore = (ImageButton) findViewById(R.id.more); - mBookmarks.setOnClickListener(this); - mNewTab.setOnClickListener(this); - mMore.setOnClickListener(this); - mScroller = (NavTabScroller) findViewById(R.id.scroller); - TabControl tc = mUiController.getTabControl(); - mTabViews = new HashMap<Tab, View>(tc.getTabCount()); - mAdapter = new TabAdapter(mContext, tc); - mScroller.setOrientation(mOrientation == Configuration.ORIENTATION_LANDSCAPE - ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); - // update state for active tab - mScroller.setAdapter(mAdapter, - mUiController.getTabControl().getTabPosition(mUi.getActiveTab())); - mScroller.setOnRemoveListener(new OnRemoveListener() { - public void onRemovePosition(int pos) { - Tab tab = mAdapter.getItem(pos); - onCloseTab(tab); - } - }); - mNewTabFab = (ImageView) findViewById(R.id.floating_action_button); - mNewTabFab.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - openNewTab(); - } - }); + LayoutInflater.from(mContext).inflate(R.layout.nav_screen, this); + setContentDescription(mContext.getResources().getString( + R.string.accessibility_transition_navscreen)); + mBookmarks = (ImageButton) findViewById(R.id.bookmarks); + mNewTab = (ImageButton) findViewById(R.id.newtab); + mMore = (ImageButton) findViewById(R.id.more); + mBookmarks.setOnClickListener(this); + mNewTab.setOnClickListener(this); + mMore.setOnClickListener(this); + mScroller = (NavTabScroller) findViewById(R.id.scroller); + TabControl tc = mUiController.getTabControl(); + mTabViews = new HashMap<Tab, View>(tc.getTabCount()); + mAdapter = new TabAdapter(mContext, tc); + mScroller.setOrientation(mOrientation == Configuration.ORIENTATION_LANDSCAPE + ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); + // update state for active tab + mScroller.setAdapter(mAdapter, + mUiController.getTabControl().getTabPosition(mUi.getActiveTab())); + mScroller.setOnRemoveListener(new OnRemoveListener() { + public void onRemovePosition(int pos) { + Tab tab = mAdapter.getItem(pos); + onCloseTab(tab); + } + }); + mNewTabFab = (ImageView) findViewById(R.id.floating_action_button); + mNewTabFab.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + openNewTab(); + } + }); } @Override diff --git a/src/com/android/browser/NavTabScroller.java b/src/com/android/browser/NavTabScroller.java index f1f8e35..b24acb3 100644 --- a/src/com/android/browser/NavTabScroller.java +++ b/src/com/android/browser/NavTabScroller.java @@ -1,18 +1,18 @@ /* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); you may not -* use this file except in compliance with the License. You may obtain a copy of -* the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations under -* the License. -*/ + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ package com.android.browser; @@ -35,535 +35,535 @@ import android.widget.LinearLayout; import com.android.browser.view.ScrollerView; /** -* custom view for displaying tabs in the nav screen -*/ + * custom view for displaying tabs in the nav screen + */ public class NavTabScroller extends ScrollerView { - static final int INVALID_POSITION = -1; - static final float[] PULL_FACTOR = { 2.5f, 0.9f }; - - interface OnRemoveListener { - public void onRemovePosition(int position); - } - - interface OnLayoutListener { - public void onLayout(int l, int t, int r, int b); - } - - private ContentLayout mContentView; - private BaseAdapter mAdapter; - private OnRemoveListener mRemoveListener; - private OnLayoutListener mLayoutListener; - private int mGap; - private int mGapPosition; - private ObjectAnimator mGapAnimator; - - // after drag animation velocity in pixels/sec - private static final float MIN_VELOCITY = 1500; - private AnimatorSet mAnimator; - - private float mFlingVelocity; - private boolean mNeedsScroll; - private int mScrollPosition; - - DecelerateInterpolator mCubic; - int mPullValue; - - public NavTabScroller(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(context); - } - - public NavTabScroller(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public NavTabScroller(Context context) { - super(context); - init(context); - } - - private void init(Context ctx) { - mCubic = new DecelerateInterpolator(1.5f); - mGapPosition = INVALID_POSITION; - setHorizontalScrollBarEnabled(false); - setVerticalScrollBarEnabled(false); - mContentView = new ContentLayout(ctx, this); - mContentView.setOrientation(LinearLayout.HORIZONTAL); - addView(mContentView); - mContentView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); - // ProGuard ! - setGap(getGap()); - mFlingVelocity = getContext().getResources().getDisplayMetrics().density - * MIN_VELOCITY; - } - - protected int getScrollValue() { - return mHorizontal ? mScrollX : mScrollY; - } - - protected void setScrollValue(int value) { - scrollTo(mHorizontal ? value : 0, mHorizontal ? 0 : value); - } - - protected NavTabView getTabView(int pos) { - return (NavTabView) mContentView.getChildAt(pos); - } - - protected boolean isHorizontal() { - return mHorizontal; - } - - public void setOrientation(int orientation) { - mContentView.setOrientation(orientation); - if (orientation == LinearLayout.HORIZONTAL) { - mContentView.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); - } else { - mContentView.setLayoutParams( - new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - } - super.setOrientation(orientation); - } - - @Override - protected void onMeasure(int wspec, int hspec) { - super.onMeasure(wspec, hspec); - calcPadding(); - } - - private void calcPadding() { - if (mAdapter.getCount() > 0) { - View v = mContentView.getChildAt(0); - if (mHorizontal) { - int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2 + 2; - mContentView.setPadding(pad, 0, pad, 0); - } else { - int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2 + 2; - mContentView.setPadding(0, pad, 0, pad); - } - } - } - - public void setAdapter(BaseAdapter adapter) { - setAdapter(adapter, 0); - } - - - public void setOnRemoveListener(OnRemoveListener l) { - mRemoveListener = l; - } - - public void setOnLayoutListener(OnLayoutListener l) { - mLayoutListener = l; - } - - protected void setAdapter(BaseAdapter adapter, int selection) { - mAdapter = adapter; - mAdapter.registerDataSetObserver(new DataSetObserver() { - - @Override - public void onChanged() { - super.onChanged(); - handleDataChanged(); - } - - @Override - public void onInvalidated() { - super.onInvalidated(); - } - }); - handleDataChanged(selection); - } - - protected ViewGroup getContentView() { - return mContentView; - } - - protected int getRelativeChildTop(int ix) { - return mContentView.getChildAt(ix).getTop() - mScrollY; - } - - protected void handleDataChanged() { - handleDataChanged(INVALID_POSITION); - } - - void handleDataChanged(int newscroll) { - int scroll = getScrollValue(); - if (mGapAnimator != null) { - mGapAnimator.cancel(); - } - mContentView.removeAllViews(); - for (int i = 0; i < mAdapter.getCount(); i++) { - View v = mAdapter.getView(i, null, mContentView); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.gravity = (mHorizontal ? Gravity.CENTER_VERTICAL : Gravity.CENTER_HORIZONTAL); - mContentView.addView(v, lp); - if (mGapPosition > INVALID_POSITION){ - adjustViewGap(v, i); - } - } - if (newscroll > INVALID_POSITION) { - newscroll = Math.min(mAdapter.getCount() - 1, newscroll); - mNeedsScroll = true; - mScrollPosition = newscroll; - requestLayout(); - } else { - setScrollValue(scroll); - } - } - - protected void finishScroller() { - mScroller.forceFinished(true); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (mNeedsScroll) { - mScroller.forceFinished(true); - snapToSelected(mScrollPosition, false); - mNeedsScroll = false; - } - if (mLayoutListener != null) { - mLayoutListener.onLayout(l, t, r, b); - mLayoutListener = null; - } - } - - void clearTabs() { - mContentView.removeAllViews(); - } - - void snapToSelected(int pos, boolean smooth) { - if (pos < 0) return; - View v = mContentView.getChildAt(pos); - if (v == null) return; - int sx = 0; - int sy = 0; - if (mHorizontal) { - sx = (v.getLeft() + v.getRight() - getWidth()) / 2; - } else { - sy = (v.getTop() + v.getBottom() - getHeight()) / 2; - } - if ((sx != mScrollX) || (sy != mScrollY)) { - if (smooth) { - smoothScrollTo(sx,sy); - } else { - scrollTo(sx, sy); - } - } - } - - protected void animateOut(View v) { - if (v == null) return; - animateOut(v, -mFlingVelocity); - } - - private void animateOut(final View v, float velocity) { - float start = mHorizontal ? v.getTranslationY() : v.getTranslationX(); - animateOut(v, velocity, start); - } - - private void animateOut(final View v, float velocity, float start) { - if ((v == null) || (mAnimator != null)) return; - final int position = mContentView.indexOfChild(v); - int target = 0; - if (velocity < 0) { - target = mHorizontal ? -getHeight() : -getWidth(); - } else { - target = mHorizontal ? getHeight() : getWidth(); - } - int distance = target - (mHorizontal ? v.getTop() : v.getLeft()); - long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity)); - int scroll = 0; - int translate = 0; - int gap = mHorizontal ? v.getWidth() : v.getHeight(); - int centerView = getViewCenter(v); - int centerScreen = getScreenCenter(); - int newpos = INVALID_POSITION; - if (centerView < centerScreen - gap / 2) { - // top view - scroll = - (centerScreen - centerView - gap); - translate = (position > 0) ? gap : 0; - newpos = position; - } else if (centerView > centerScreen + gap / 2) { - // bottom view - scroll = - (centerScreen + gap - centerView); - if (position < mAdapter.getCount() - 1) { - translate = -gap; - } - } else { - // center view - scroll = - (centerScreen - centerView); - if (position < mAdapter.getCount() - 1) { - translate = -gap; - } else { - scroll -= gap; - } - } - mGapPosition = position; - final int pos = newpos; - ObjectAnimator trans = ObjectAnimator.ofFloat(v, - (mHorizontal ? TRANSLATION_Y : TRANSLATION_X), start, target); - ObjectAnimator alpha = ObjectAnimator.ofFloat(v, ALPHA, getAlpha(v,start), - getAlpha(v,target)); - AnimatorSet set1 = new AnimatorSet(); - set1.playTogether(trans, alpha); - set1.setDuration(duration); - mAnimator = new AnimatorSet(); - ObjectAnimator trans2 = null; - ObjectAnimator scroll1 = null; - if (scroll != 0) { - if (mHorizontal) { - scroll1 = ObjectAnimator.ofInt(this, "scrollX", getScrollX(), getScrollX() + scroll); - } else { - scroll1 = ObjectAnimator.ofInt(this, "scrollY", getScrollY(), getScrollY() + scroll); - } - } - if (translate != 0) { - trans2 = ObjectAnimator.ofInt(this, "gap", 0, translate); - } - final int duration2 = 200; - if (scroll1 != null) { - if (trans2 != null) { - AnimatorSet set2 = new AnimatorSet(); - set2.playTogether(scroll1, trans2); - set2.setDuration(duration2); - mAnimator.playSequentially(set1, set2); - } else { - scroll1.setDuration(duration2); - mAnimator.playSequentially(set1, scroll1); - } - } else { - if (trans2 != null) { - trans2.setDuration(duration2); - mAnimator.playSequentially(set1, trans2); - } - } - mAnimator.addListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator a) { - if (mRemoveListener != null) { - mRemoveListener.onRemovePosition(position); - mAnimator = null; - mGapPosition = INVALID_POSITION; - mGap = 0; - handleDataChanged(pos); + static final int INVALID_POSITION = -1; + static final float[] PULL_FACTOR = { 2.5f, 0.9f }; + + interface OnRemoveListener { + public void onRemovePosition(int position); + } + + interface OnLayoutListener { + public void onLayout(int l, int t, int r, int b); + } + + private ContentLayout mContentView; + private BaseAdapter mAdapter; + private OnRemoveListener mRemoveListener; + private OnLayoutListener mLayoutListener; + private int mGap; + private int mGapPosition; + private ObjectAnimator mGapAnimator; + + // after drag animation velocity in pixels/sec + private static final float MIN_VELOCITY = 1500; + private AnimatorSet mAnimator; + + private float mFlingVelocity; + private boolean mNeedsScroll; + private int mScrollPosition; + + DecelerateInterpolator mCubic; + int mPullValue; + + public NavTabScroller(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context); + } + + public NavTabScroller(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public NavTabScroller(Context context) { + super(context); + init(context); + } + + private void init(Context ctx) { + mCubic = new DecelerateInterpolator(1.5f); + mGapPosition = INVALID_POSITION; + setHorizontalScrollBarEnabled(false); + setVerticalScrollBarEnabled(false); + mContentView = new ContentLayout(ctx, this); + mContentView.setOrientation(LinearLayout.HORIZONTAL); + addView(mContentView); + mContentView.setLayoutParams( + new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); + // ProGuard ! + setGap(getGap()); + mFlingVelocity = getContext().getResources().getDisplayMetrics().density + * MIN_VELOCITY; + } + + protected int getScrollValue() { + return mHorizontal ? mScrollX : mScrollY; + } + + protected void setScrollValue(int value) { + scrollTo(mHorizontal ? value : 0, mHorizontal ? 0 : value); + } + + protected NavTabView getTabView(int pos) { + return (NavTabView) mContentView.getChildAt(pos); + } + + protected boolean isHorizontal() { + return mHorizontal; + } + + public void setOrientation(int orientation) { + mContentView.setOrientation(orientation); + if (orientation == LinearLayout.HORIZONTAL) { + mContentView.setLayoutParams( + new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); + } else { + mContentView.setLayoutParams( + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); } - } - }); - mAnimator.start(); - } - - public void setGap(int gap) { - if (mGapPosition != INVALID_POSITION) { - mGap = gap; - postInvalidate(); - } - } - - public int getGap() { - return mGap; - } - - void adjustGap() { - for (int i = 0; i < mContentView.getChildCount(); i++) { - final View child = mContentView.getChildAt(i); - adjustViewGap(child, i); - } - } - - private void adjustViewGap(View view, int pos) { - if ((mGap < 0 && pos > mGapPosition) - || (mGap > 0 && pos < mGapPosition)) { - if (mHorizontal) { - view.setTranslationX(mGap); - } else { - view.setTranslationY(mGap); - } - } - } - - private int getViewCenter(View v) { - if (mHorizontal) { - return v.getLeft() + v.getWidth() / 2; - } else { - return v.getTop() + v.getHeight() / 2; - } - } - - private int getScreenCenter() { - if (mHorizontal) { - return getScrollX() + getWidth() / 2; - } else { - return getScrollY() + getHeight() / 2; - } - } - - @Override - public void draw(Canvas canvas) { - if (mGapPosition > INVALID_POSITION) { - adjustGap(); - } - super.draw(canvas); - } - - @Override - protected View findViewAt(int x, int y) { - x += mScrollX; - y += mScrollY; - final int count = mContentView.getChildCount(); - for (int i = count - 1; i >= 0; i--) { - View child = mContentView.getChildAt(i); - if (child.getVisibility() == View.VISIBLE) { - if ((x >= child.getLeft()) && (x < child.getRight()) - && (y >= child.getTop()) && (y < child.getBottom())) { - return child; + super.setOrientation(orientation); + } + + @Override + protected void onMeasure(int wspec, int hspec) { + super.onMeasure(wspec, hspec); + calcPadding(); + } + + private void calcPadding() { + if (mAdapter.getCount() > 0) { + View v = mContentView.getChildAt(0); + if (mHorizontal) { + int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2 + 2; + mContentView.setPadding(pad, 0, pad, 0); + } else { + int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2 + 2; + mContentView.setPadding(0, pad, 0, pad); + } } - } - } - return null; - } - - @Override - protected void onOrthoDrag(View v, float distance) { - if ((v != null) && (mAnimator == null)) { - offsetView(v, distance); - } - } - - @Override - protected void onOrthoDragFinished(View downView) { - if (mAnimator != null) return; - if (mIsOrthoDragged && downView != null) { - // offset - float diff = mHorizontal ? downView.getTranslationY() : downView.getTranslationX(); - if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) { - // remove it - animateOut(downView, Math.signum(diff) * mFlingVelocity, diff); - } else { - // snap back - offsetView(downView, 0); - } - } - } - - @Override - protected void onOrthoFling(View v, float velocity) { - if (v == null) return; - if (mAnimator == null && Math.abs(velocity) > mFlingVelocity / 2) { - animateOut(v, velocity); - } else { - offsetView(v, 0); - } - } - - private void offsetView(View v, float distance) { - v.setAlpha(getAlpha(v, distance)); - if (mHorizontal) { - v.setTranslationY(distance); - } else { - v.setTranslationX(distance); - } - } - - private float getAlpha(View v, float distance) { - return 1 - (float) Math.abs(distance) / (mHorizontal ? v.getHeight() : v.getWidth()); - } - - private float ease(DecelerateInterpolator inter, float value, float start, - float dist, float duration) { - return start + dist * inter.getInterpolation(value / duration); - } - - @Override - protected void onPull(int delta) { - boolean layer = false; - int count = 2; - if (delta == 0 && mPullValue == 0) return; - if (delta == 0 && mPullValue != 0) { - // reset - for (int i = 0; i < count; i++) { - View child = mContentView.getChildAt((mPullValue < 0) - ? i - : mContentView.getChildCount() - 1 - i); - if (child == null) break; - ObjectAnimator trans = ObjectAnimator.ofFloat(child, - mHorizontal ? "translationX" : "translationY", - mHorizontal ? getTranslationX() : getTranslationY(), - 0); - ObjectAnimator rot = ObjectAnimator.ofFloat(child, - mHorizontal ? "rotationY" : "rotationX", - mHorizontal ? getRotationY() : getRotationX(), - 0); - AnimatorSet set = new AnimatorSet(); - set.playTogether(trans, rot); - set.setDuration(100); - set.start(); - } - mPullValue = 0; - } else { - if (mPullValue == 0) { - layer = true; - } - mPullValue += delta; - } - final int height = mHorizontal ? getWidth() : getHeight(); - int oscroll = Math.abs(mPullValue); - int factor = (mPullValue <= 0) ? 1 : -1; - for (int i = 0; i < count; i++) { - View child = mContentView.getChildAt((mPullValue < 0) - ? i - : mContentView.getChildCount() - 1 - i); - if (child == null) break; - if (layer) { - } - float k = PULL_FACTOR[i]; - float rot = -factor * ease(mCubic, oscroll, 0, k * 2, height); - int y = factor * (int) ease(mCubic, oscroll, 0, k*20, height); - if (mHorizontal) { - child.setTranslationX(y); - } else { - child.setTranslationY(y); - } - if (mHorizontal) { - child.setRotationY(-rot); - } else { - child.setRotationX(rot); - } - } - } - - static class ContentLayout extends LinearLayout { - - NavTabScroller mScroller; - - public ContentLayout(Context context, NavTabScroller scroller) { - super(context); - mScroller = scroller; + } + + public void setAdapter(BaseAdapter adapter) { + setAdapter(adapter, 0); + } + + + public void setOnRemoveListener(OnRemoveListener l) { + mRemoveListener = l; + } + + public void setOnLayoutListener(OnLayoutListener l) { + mLayoutListener = l; + } + + protected void setAdapter(BaseAdapter adapter, int selection) { + mAdapter = adapter; + mAdapter.registerDataSetObserver(new DataSetObserver() { + + @Override + public void onChanged() { + super.onChanged(); + handleDataChanged(); + } + + @Override + public void onInvalidated() { + super.onInvalidated(); + } + }); + handleDataChanged(selection); + } + + protected ViewGroup getContentView() { + return mContentView; + } + + protected int getRelativeChildTop(int ix) { + return mContentView.getChildAt(ix).getTop() - mScrollY; + } + + protected void handleDataChanged() { + handleDataChanged(INVALID_POSITION); + } + + void handleDataChanged(int newscroll) { + int scroll = getScrollValue(); + if (mGapAnimator != null) { + mGapAnimator.cancel(); + } + mContentView.removeAllViews(); + for (int i = 0; i < mAdapter.getCount(); i++) { + View v = mAdapter.getView(i, null, mContentView); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp.gravity = (mHorizontal ? Gravity.CENTER_VERTICAL : Gravity.CENTER_HORIZONTAL); + mContentView.addView(v, lp); + if (mGapPosition > INVALID_POSITION){ + adjustViewGap(v, i); + } + } + if (newscroll > INVALID_POSITION) { + newscroll = Math.min(mAdapter.getCount() - 1, newscroll); + mNeedsScroll = true; + mScrollPosition = newscroll; + requestLayout(); + } else { + setScrollValue(scroll); + } + } + + protected void finishScroller() { + mScroller.forceFinished(true); } @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (mScroller.getGap() != 0) { - View v = getChildAt(0); - if (v != null) { - if (mScroller.isHorizontal()) { - int total = v.getMeasuredWidth() + getMeasuredWidth(); - setMeasuredDimension(total, getMeasuredHeight()); - } else { - int total = v.getMeasuredHeight() + getMeasuredHeight(); - setMeasuredDimension(getMeasuredWidth(), total); - } + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (mNeedsScroll) { + mScroller.forceFinished(true); + snapToSelected(mScrollPosition, false); + mNeedsScroll = false; } + if (mLayoutListener != null) { + mLayoutListener.onLayout(l, t, r, b); + mLayoutListener = null; + } + } - } + void clearTabs() { + mContentView.removeAllViews(); } - } + void snapToSelected(int pos, boolean smooth) { + if (pos < 0) return; + View v = mContentView.getChildAt(pos); + if (v == null) return; + int sx = 0; + int sy = 0; + if (mHorizontal) { + sx = (v.getLeft() + v.getRight() - getWidth()) / 2; + } else { + sy = (v.getTop() + v.getBottom() - getHeight()) / 2; + } + if ((sx != mScrollX) || (sy != mScrollY)) { + if (smooth) { + smoothScrollTo(sx,sy); + } else { + scrollTo(sx, sy); + } + } + } + + protected void animateOut(View v) { + if (v == null) return; + animateOut(v, -mFlingVelocity); + } + + private void animateOut(final View v, float velocity) { + float start = mHorizontal ? v.getTranslationY() : v.getTranslationX(); + animateOut(v, velocity, start); + } + + private void animateOut(final View v, float velocity, float start) { + if ((v == null) || (mAnimator != null)) return; + final int position = mContentView.indexOfChild(v); + int target = 0; + if (velocity < 0) { + target = mHorizontal ? -getHeight() : -getWidth(); + } else { + target = mHorizontal ? getHeight() : getWidth(); + } + int distance = target - (mHorizontal ? v.getTop() : v.getLeft()); + long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity)); + int scroll = 0; + int translate = 0; + int gap = mHorizontal ? v.getWidth() : v.getHeight(); + int centerView = getViewCenter(v); + int centerScreen = getScreenCenter(); + int newpos = INVALID_POSITION; + if (centerView < centerScreen - gap / 2) { + // top view + scroll = - (centerScreen - centerView - gap); + translate = (position > 0) ? gap : 0; + newpos = position; + } else if (centerView > centerScreen + gap / 2) { + // bottom view + scroll = - (centerScreen + gap - centerView); + if (position < mAdapter.getCount() - 1) { + translate = -gap; + } + } else { + // center view + scroll = - (centerScreen - centerView); + if (position < mAdapter.getCount() - 1) { + translate = -gap; + } else { + scroll -= gap; + } + } + mGapPosition = position; + final int pos = newpos; + ObjectAnimator trans = ObjectAnimator.ofFloat(v, + (mHorizontal ? TRANSLATION_Y : TRANSLATION_X), start, target); + ObjectAnimator alpha = ObjectAnimator.ofFloat(v, ALPHA, getAlpha(v,start), + getAlpha(v,target)); + AnimatorSet set1 = new AnimatorSet(); + set1.playTogether(trans, alpha); + set1.setDuration(duration); + mAnimator = new AnimatorSet(); + ObjectAnimator trans2 = null; + ObjectAnimator scroll1 = null; + if (scroll != 0) { + if (mHorizontal) { + scroll1 = ObjectAnimator.ofInt(this, "scrollX", getScrollX(), getScrollX() + scroll); + } else { + scroll1 = ObjectAnimator.ofInt(this, "scrollY", getScrollY(), getScrollY() + scroll); + } + } + if (translate != 0) { + trans2 = ObjectAnimator.ofInt(this, "gap", 0, translate); + } + final int duration2 = 200; + if (scroll1 != null) { + if (trans2 != null) { + AnimatorSet set2 = new AnimatorSet(); + set2.playTogether(scroll1, trans2); + set2.setDuration(duration2); + mAnimator.playSequentially(set1, set2); + } else { + scroll1.setDuration(duration2); + mAnimator.playSequentially(set1, scroll1); + } + } else { + if (trans2 != null) { + trans2.setDuration(duration2); + mAnimator.playSequentially(set1, trans2); + } + } + mAnimator.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + if (mRemoveListener != null) { + mRemoveListener.onRemovePosition(position); + mAnimator = null; + mGapPosition = INVALID_POSITION; + mGap = 0; + handleDataChanged(pos); + } + } + }); + mAnimator.start(); + } + + public void setGap(int gap) { + if (mGapPosition != INVALID_POSITION) { + mGap = gap; + postInvalidate(); + } + } + + public int getGap() { + return mGap; + } + + void adjustGap() { + for (int i = 0; i < mContentView.getChildCount(); i++) { + final View child = mContentView.getChildAt(i); + adjustViewGap(child, i); + } + } + + private void adjustViewGap(View view, int pos) { + if ((mGap < 0 && pos > mGapPosition) + || (mGap > 0 && pos < mGapPosition)) { + if (mHorizontal) { + view.setTranslationX(mGap); + } else { + view.setTranslationY(mGap); + } + } + } + + private int getViewCenter(View v) { + if (mHorizontal) { + return v.getLeft() + v.getWidth() / 2; + } else { + return v.getTop() + v.getHeight() / 2; + } + } + + private int getScreenCenter() { + if (mHorizontal) { + return getScrollX() + getWidth() / 2; + } else { + return getScrollY() + getHeight() / 2; + } + } + + @Override + public void draw(Canvas canvas) { + if (mGapPosition > INVALID_POSITION) { + adjustGap(); + } + super.draw(canvas); + } + + @Override + protected View findViewAt(int x, int y) { + x += mScrollX; + y += mScrollY; + final int count = mContentView.getChildCount(); + for (int i = count - 1; i >= 0; i--) { + View child = mContentView.getChildAt(i); + if (child.getVisibility() == View.VISIBLE) { + if ((x >= child.getLeft()) && (x < child.getRight()) + && (y >= child.getTop()) && (y < child.getBottom())) { + return child; + } + } + } + return null; + } + + @Override + protected void onOrthoDrag(View v, float distance) { + if ((v != null) && (mAnimator == null)) { + offsetView(v, distance); + } + } + + @Override + protected void onOrthoDragFinished(View downView) { + if (mAnimator != null) return; + if (mIsOrthoDragged && downView != null) { + // offset + float diff = mHorizontal ? downView.getTranslationY() : downView.getTranslationX(); + if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) { + // remove it + animateOut(downView, Math.signum(diff) * mFlingVelocity, diff); + } else { + // snap back + offsetView(downView, 0); + } + } + } + + @Override + protected void onOrthoFling(View v, float velocity) { + if (v == null) return; + if (mAnimator == null && Math.abs(velocity) > mFlingVelocity / 2) { + animateOut(v, velocity); + } else { + offsetView(v, 0); + } + } + + private void offsetView(View v, float distance) { + v.setAlpha(getAlpha(v, distance)); + if (mHorizontal) { + v.setTranslationY(distance); + } else { + v.setTranslationX(distance); + } + } + + private float getAlpha(View v, float distance) { + return 1 - (float) Math.abs(distance) / (mHorizontal ? v.getHeight() : v.getWidth()); + } + + private float ease(DecelerateInterpolator inter, float value, float start, + float dist, float duration) { + return start + dist * inter.getInterpolation(value / duration); + } + + @Override + protected void onPull(int delta) { + boolean layer = false; + int count = 2; + if (delta == 0 && mPullValue == 0) return; + if (delta == 0 && mPullValue != 0) { + // reset + for (int i = 0; i < count; i++) { + View child = mContentView.getChildAt((mPullValue < 0) + ? i + : mContentView.getChildCount() - 1 - i); + if (child == null) break; + ObjectAnimator trans = ObjectAnimator.ofFloat(child, + mHorizontal ? "translationX" : "translationY", + mHorizontal ? getTranslationX() : getTranslationY(), + 0); + ObjectAnimator rot = ObjectAnimator.ofFloat(child, + mHorizontal ? "rotationY" : "rotationX", + mHorizontal ? getRotationY() : getRotationX(), + 0); + AnimatorSet set = new AnimatorSet(); + set.playTogether(trans, rot); + set.setDuration(100); + set.start(); + } + mPullValue = 0; + } else { + if (mPullValue == 0) { + layer = true; + } + mPullValue += delta; + } + final int height = mHorizontal ? getWidth() : getHeight(); + int oscroll = Math.abs(mPullValue); + int factor = (mPullValue <= 0) ? 1 : -1; + for (int i = 0; i < count; i++) { + View child = mContentView.getChildAt((mPullValue < 0) + ? i + : mContentView.getChildCount() - 1 - i); + if (child == null) break; + if (layer) { + } + float k = PULL_FACTOR[i]; + float rot = -factor * ease(mCubic, oscroll, 0, k * 2, height); + int y = factor * (int) ease(mCubic, oscroll, 0, k*20, height); + if (mHorizontal) { + child.setTranslationX(y); + } else { + child.setTranslationY(y); + } + if (mHorizontal) { + child.setRotationY(-rot); + } else { + child.setRotationX(rot); + } + } + } + + static class ContentLayout extends LinearLayout { + + NavTabScroller mScroller; + + public ContentLayout(Context context, NavTabScroller scroller) { + super(context); + mScroller = scroller; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mScroller.getGap() != 0) { + View v = getChildAt(0); + if (v != null) { + if (mScroller.isHorizontal()) { + int total = v.getMeasuredWidth() + getMeasuredWidth(); + setMeasuredDimension(total, getMeasuredHeight()); + } else { + int total = v.getMeasuredHeight() + getMeasuredHeight(); + setMeasuredDimension(getMeasuredWidth(), total); + } + } + + } + } + + } } |