Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.contextmenu; | 5 package org.chromium.chrome.browser.contextmenu; |
| 6 | 6 |
| 7 import android.app.ActionBar.LayoutParams; | |
| 7 import android.app.Activity; | 8 import android.app.Activity; |
| 8 import android.app.Dialog; | 9 import android.app.Dialog; |
| 9 import android.content.DialogInterface; | 10 import android.content.DialogInterface; |
| 10 import android.content.res.Resources; | 11 import android.content.res.Resources; |
| 11 import android.graphics.Bitmap; | 12 import android.graphics.Bitmap; |
| 12 import android.graphics.Canvas; | 13 import android.graphics.Canvas; |
| 14 import android.graphics.Color; | |
| 13 import android.graphics.Shader; | 15 import android.graphics.Shader; |
| 14 import android.graphics.drawable.BitmapDrawable; | 16 import android.graphics.drawable.BitmapDrawable; |
| 17 import android.graphics.drawable.ColorDrawable; | |
| 15 import android.graphics.drawable.Drawable; | 18 import android.graphics.drawable.Drawable; |
| 16 import android.support.design.widget.TabLayout; | 19 import android.support.design.widget.TabLayout; |
| 17 import android.support.v4.view.ViewPager; | 20 import android.support.v4.view.ViewPager; |
| 21 import android.support.v4.view.animation.LinearOutSlowInInterpolator; | |
| 18 import android.support.v7.app.AlertDialog; | 22 import android.support.v7.app.AlertDialog; |
| 19 import android.text.TextUtils; | 23 import android.text.TextUtils; |
| 20 import android.util.Pair; | 24 import android.util.Pair; |
| 25 import android.view.Gravity; | |
| 21 import android.view.LayoutInflater; | 26 import android.view.LayoutInflater; |
| 22 import android.view.View; | 27 import android.view.View; |
| 28 import android.view.View.OnClickListener; | |
| 29 import android.view.View.OnLayoutChangeListener; | |
| 23 import android.view.ViewGroup; | 30 import android.view.ViewGroup; |
| 31 import android.view.Window; | |
| 32 import android.view.animation.Animation; | |
| 33 import android.view.animation.Animation.AnimationListener; | |
| 34 import android.view.animation.ScaleAnimation; | |
| 24 import android.widget.AdapterView; | 35 import android.widget.AdapterView; |
| 25 import android.widget.BaseAdapter; | 36 import android.widget.BaseAdapter; |
| 37 import android.widget.FrameLayout; | |
| 26 import android.widget.ImageView; | 38 import android.widget.ImageView; |
| 27 import android.widget.ListView; | 39 import android.widget.ListView; |
| 28 import android.widget.TextView; | 40 import android.widget.TextView; |
| 29 | 41 |
| 30 import org.chromium.base.ApiCompatibilityUtils; | 42 import org.chromium.base.ApiCompatibilityUtils; |
| 31 import org.chromium.base.Callback; | 43 import org.chromium.base.Callback; |
| 32 import org.chromium.base.VisibleForTesting; | 44 import org.chromium.base.VisibleForTesting; |
| 33 import org.chromium.chrome.R; | 45 import org.chromium.chrome.R; |
| 46 import org.chromium.chrome.browser.widget.AlwaysDismissedDialog; | |
| 47 import org.chromium.content.browser.ContentViewCore; | |
| 34 | 48 |
| 35 import java.util.ArrayList; | 49 import java.util.ArrayList; |
| 36 import java.util.List; | 50 import java.util.List; |
| 37 | 51 |
| 38 /** | 52 /** |
| 39 * A custom dialog that separates each group into separate tabs. It uses a dialo g instead. | 53 * A custom dialog that separates each group into separate tabs. It uses a dialo g instead. |
| 40 */ | 54 */ |
| 41 public class TabularContextMenuUi implements ContextMenuUi, AdapterView.OnItemCl ickListener { | 55 public class TabularContextMenuUi implements ContextMenuUi, AdapterView.OnItemCl ickListener { |
| 42 private Dialog mDialog; | 56 private Dialog mDialog; |
| 43 private Callback<Integer> mCallback; | 57 private Callback<Integer> mCallback; |
| 44 private int mMenuItemHeight; | 58 private int mMenuItemHeight; |
| 45 private ImageView mHeaderImageView; | 59 private ImageView mHeaderImageView; |
| 46 private Runnable mOnShareItemClicked; | 60 private Runnable mOnShareItemClicked; |
| 61 private View mPagerView; | |
| 62 | |
| 63 private float mContextMenuSourceX; | |
| 64 private float mContextMenuSourceY; | |
| 65 private int mContextMenuLocationOnScreen; | |
| 66 private int mContextMenuHeight = -1; | |
| 67 private int mContextMenuWidth; | |
| 68 private ContentViewCore mContentViewCore; | |
| 47 | 69 |
| 48 public TabularContextMenuUi(Runnable onShareItemClicked) { | 70 public TabularContextMenuUi(Runnable onShareItemClicked) { |
| 49 mOnShareItemClicked = onShareItemClicked; | 71 mOnShareItemClicked = onShareItemClicked; |
| 50 } | 72 } |
| 51 | 73 |
| 52 @Override | 74 @Override |
| 53 public void displayMenu(Activity activity, ContextMenuParams params, | 75 public void displayMenu(Activity activity, ContextMenuParams params, |
| 54 List<Pair<Integer, List<ContextMenuItem>>> items, Callback<Integer> onItemClicked, | 76 List<Pair<Integer, List<ContextMenuItem>>> items, Callback<Integer> onItemClicked, |
| 55 final Runnable onMenuShown, final Runnable onMenuClosed) { | 77 final Runnable onMenuShown, final Runnable onMenuClosed) { |
| 56 mCallback = onItemClicked; | 78 mCallback = onItemClicked; |
| 57 mDialog = createDialog(activity, params, items); | 79 mDialog = createDialog(activity, params, items); |
| 58 | 80 |
| 59 mDialog.getWindow().setBackgroundDrawable(ApiCompatibilityUtils.getDrawa ble( | |
| 60 activity.getResources(), R.drawable.white_with_rounded_corners)) ; | |
| 61 | |
| 62 mDialog.setOnShowListener(new DialogInterface.OnShowListener() { | 81 mDialog.setOnShowListener(new DialogInterface.OnShowListener() { |
| 63 @Override | 82 @Override |
| 64 public void onShow(DialogInterface dialogInterface) { | 83 public void onShow(DialogInterface dialogInterface) { |
| 65 onMenuShown.run(); | 84 onMenuShown.run(); |
| 66 } | 85 } |
| 67 }); | 86 }); |
| 68 | 87 |
| 69 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { | 88 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
| 70 @Override | 89 @Override |
| 71 public void onDismiss(DialogInterface dialogInterface) { | 90 public void onDismiss(DialogInterface dialogInterface) { |
| 72 onMenuClosed.run(); | 91 onMenuClosed.run(); |
| 73 } | 92 } |
| 74 }); | 93 }); |
| 75 | 94 |
| 95 Window dialogWindow = mDialog.getWindow(); | |
| 96 dialogWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)) ; | |
| 97 dialogWindow.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PAR ENT); | |
| 98 | |
| 99 float density = Resources.getSystem().getDisplayMetrics().density; | |
| 100 final float touchPointX = params.getX() * density; | |
| 101 final float touchPointY = params.getY() * density; | |
| 102 | |
| 76 mDialog.show(); | 103 mDialog.show(); |
| 104 mPagerView.setVisibility(View.INVISIBLE); | |
|
Theresa
2017/05/19 17:19:30
nit: I would move this visibility change and the l
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 105 mPagerView.addOnLayoutChangeListener(new OnLayoutChangeListener() { | |
| 106 | |
| 107 @Override | |
| 108 public void onLayoutChange(View v, int left, int top, int right, int bottom, | |
| 109 int oldLeft, int oldTop, int oldRight, int oldBottom) { | |
| 110 if (mContextMenuHeight == -1) { | |
|
Theresa
2017/05/19 17:19:30
Rather than relying on mContextMenuHeight == -1, l
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 111 mContextMenuHeight = v.getHeight(); | |
| 112 initializeAnimationAndRevealView(touchPointX, touchPointY); | |
| 113 } | |
| 114 } | |
| 115 }); | |
| 77 } | 116 } |
| 78 | 117 |
| 79 /** | 118 /** |
| 80 * Returns the fully complete dialog based off the params and the itemGroups . | 119 * Returns the fully complete dialog based off the params and the itemGroups . |
| 81 * @param activity Used to inflate the dialog. | 120 * @param activity Used to inflate the dialog. |
| 82 * @param params Used to get the header title. | 121 * @param params Used to get the header title. |
| 83 * @param itemGroups If there is more than one group it will create a paged view. | 122 * @param itemGroups If there is more than one group it will create a paged view. |
| 84 * @return Returns a final dialog that does not have a background can be dis played using | 123 * @return Returns a final dialog that does not have a background can be dis played using |
| 85 * {@link AlertDialog#show()}. | 124 * {@link AlertDialog#show()}. |
| 86 */ | 125 */ |
| 126 @SuppressWarnings("deprecation") | |
|
Theresa
2017/05/19 17:19:30
What method is deprecated?
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 87 private Dialog createDialog(Activity activity, ContextMenuParams params, | 127 private Dialog createDialog(Activity activity, ContextMenuParams params, |
| 88 List<Pair<Integer, List<ContextMenuItem>>> itemGroups) { | 128 List<Pair<Integer, List<ContextMenuItem>>> itemGroups) { |
| 89 Dialog dialog = new Dialog(activity); | 129 final Dialog dialog = new AlwaysDismissedDialog(activity, R.style.Dialog WhenLarge); |
| 90 dialog.setContentView(createPagerView(activity, params, itemGroups)); | 130 |
| 131 dialog.findViewById(android.R.id.content).setOnClickListener(new OnClick Listener() { | |
| 132 @Override | |
| 133 public void onClick(View v) { | |
| 134 int[] outLocation = new int[2]; | |
| 135 mPagerView.getLocationOnScreen(outLocation); | |
| 136 mContextMenuSourceY = | |
| 137 mContextMenuSourceY + (mContextMenuLocationOnScreen - ou tLocation[1]); | |
| 138 Animation exitAnimation = getScaleAnimation(false); | |
| 139 exitAnimation.setAnimationListener(new AnimationListener() { | |
| 140 | |
| 141 @Override | |
| 142 public void onAnimationStart(Animation animation) {} | |
| 143 | |
| 144 @Override | |
| 145 public void onAnimationRepeat(Animation animation) {} | |
| 146 | |
| 147 @Override | |
| 148 public void onAnimationEnd(Animation animation) { | |
| 149 dialog.dismiss(); | |
| 150 } | |
| 151 }); | |
| 152 mPagerView.startAnimation(exitAnimation); | |
| 153 mContextMenuHeight = -1; | |
|
Theresa
2017/05/19 17:19:30
Each time the context menu is displayed, a new Dia
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 154 } | |
| 155 }); | |
| 156 | |
| 157 FrameLayout mFullContainer = new FrameLayout(activity); | |
| 158 mFullContainer.setBackgroundColor(ApiCompatibilityUtils.getColor( | |
| 159 activity.getResources(), R.color.modal_dialog_scrim_color)); | |
| 160 | |
| 161 mContextMenuWidth = | |
| 162 (int) Math.min(Resources.getSystem().getDisplayMetrics().widthPi xels * 0.75, 1000); | |
|
Theresa
2017/05/19 17:19:30
0.75 should be defined as private static final MAX
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 163 | |
| 164 FrameLayout.LayoutParams layoutParams = | |
| 165 new FrameLayout.LayoutParams(mContextMenuWidth, LayoutParams.MAT CH_PARENT); | |
| 166 layoutParams.gravity = Gravity.CENTER; | |
| 167 | |
| 168 mPagerView = createPagerView(activity, params, itemGroups); | |
| 169 | |
| 170 mFullContainer.addView(mPagerView, layoutParams); | |
| 171 dialog.addContentView(mFullContainer, | |
| 172 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_P ARENT)); | |
| 173 | |
| 91 return dialog; | 174 return dialog; |
| 92 } | 175 } |
| 93 | 176 |
| 94 /** | 177 /** |
| 95 * Creates a ViewPageAdapter based off the given list of views. | 178 * Creates a ViewPageAdapter based off the given list of views. |
| 96 * @param activity Used to inflate the new ViewPager | 179 * @param activity Used to inflate the new ViewPager |
| 97 * @param params Used to get the header text. | 180 * @param params Used to get the header text. |
| 98 * @param itemGroups The list of views to put into the ViewPager. The string is the title of the | 181 * @param itemGroups The list of views to put into the ViewPager. The string is the title of the |
| 99 * tab | 182 * tab |
| 100 * @return Returns a complete tabular context menu view. | 183 * @return Returns a complete tabular context menu view. |
| 101 */ | 184 */ |
| 102 @VisibleForTesting | 185 @VisibleForTesting |
| 103 View createPagerView(Activity activity, ContextMenuParams params, | 186 View createPagerView(Activity activity, ContextMenuParams params, |
| 104 List<Pair<Integer, List<ContextMenuItem>>> itemGroups) { | 187 List<Pair<Integer, List<ContextMenuItem>>> itemGroups) { |
| 105 View view = LayoutInflater.from(activity).inflate(R.layout.tabular_conte xt_menu, null); | 188 View view = LayoutInflater.from(activity).inflate(R.layout.tabular_conte xt_menu, null); |
| 189 view.findViewById(R.id.custom_pager) | |
| 190 .setBackgroundResource(R.drawable.white_with_rounded_corners); | |
|
Theresa
2017/05/19 17:19:30
Let's set the background in tabular_context_menu.x
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 106 | 191 |
| 107 List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>(); | 192 List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>(); |
| 108 int maxCount = 0; | 193 int maxCount = 0; |
| 109 for (int i = 0; i < itemGroups.size(); i++) { | 194 for (int i = 0; i < itemGroups.size(); i++) { |
| 110 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); | 195 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); |
| 111 maxCount = Math.max(maxCount, itemGroup.second.size()); | 196 maxCount = Math.max(maxCount, itemGroup.second.size()); |
| 112 } | 197 } |
| 113 for (int i = 0; i < itemGroups.size(); i++) { | 198 for (int i = 0; i < itemGroups.size(); i++) { |
| 114 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); | 199 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); |
| 115 // TODO(tedchoc): Pass the ContextMenuGroup identifier to determine if it's an image. | 200 // TODO(tedchoc): Pass the ContextMenuGroup identifier to determine if it's an image. |
| 116 boolean isImageTab = itemGroup.first == R.string.contextmenu_image_t itle; | 201 boolean isImageTab = itemGroup.first == R.string.contextmenu_image_t itle; |
| 117 viewGroups.add(new Pair<>(activity.getString(itemGroup.first), | 202 viewGroups.add(new Pair<>(activity.getString(itemGroup.first), |
| 118 createContextMenuPageUi( | 203 createContextMenuPageUi( |
| 119 activity, params, itemGroup.second, isImageTab, maxC ount))); | 204 activity, params, itemGroup.second, isImageTab, maxC ount))); |
| 120 } | 205 } |
| 121 if (itemGroups.size() == 1) { | |
| 122 viewGroups.get(0) | |
| 123 .second.getChildAt(0) | |
| 124 .findViewById(R.id.context_header_layout) | |
| 125 .setBackgroundResource(R.color.google_grey_100); | |
| 126 } | |
| 127 | 206 |
| 128 TabularContextMenuViewPager pager = | 207 TabularContextMenuViewPager pager = |
| 129 (TabularContextMenuViewPager) view.findViewById(R.id.custom_page r); | 208 (TabularContextMenuViewPager) view.findViewById(R.id.custom_page r); |
| 130 pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups)); | 209 pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups)); |
| 131 | |
| 132 TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout); | 210 TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout); |
| 133 if (itemGroups.size() <= 1) { | 211 if (itemGroups.size() <= 1) { |
| 134 tabLayout.setVisibility(View.GONE); | 212 tabLayout.setVisibility(View.GONE); |
| 135 } else { | 213 } else { |
| 214 tabLayout.setBackgroundResource(R.drawable.grey_with_top_rounded_cor ners); | |
| 136 tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.cust om_pager)); | 215 tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.cust om_pager)); |
| 137 } | 216 } |
| 138 | 217 |
| 139 return view; | 218 return view; |
| 140 } | 219 } |
| 141 | 220 |
| 142 /** | 221 /** |
| 143 * Creates the view of a context menu. Based off the Context Type, it'll adj ust the list of | 222 * Creates the view of a context menu. Based off the Context Type, it'll adj ust the list of |
| 144 * items and display only the ones that'll be on that specific group. | 223 * items and display only the ones that'll be on that specific group. |
| 145 * @param activity Used to get the resources of an item. | 224 * @param activity Used to get the resources of an item. |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 if (mMenuItemHeight == 0 && !listAdapter.isEmpty()) { | 335 if (mMenuItemHeight == 0 && !listAdapter.isEmpty()) { |
| 257 View view = listAdapter.getView(0, null, listView); | 336 View view = listAdapter.getView(0, null, listView); |
| 258 view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UN SPECIFIED), | 337 view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UN SPECIFIED), |
| 259 View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECI FIED)); | 338 View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECI FIED)); |
| 260 mMenuItemHeight = view.getMeasuredHeight(); | 339 mMenuItemHeight = view.getMeasuredHeight(); |
| 261 } | 340 } |
| 262 return totalHeight + mMenuItemHeight * maxCount; | 341 return totalHeight + mMenuItemHeight * maxCount; |
| 263 } | 342 } |
| 264 | 343 |
| 265 /** | 344 /** |
| 345 * @param touchPointX The x-coordinate of the pixel where the touch was regi stered | |
| 346 * @param touchPointY The y-coordinate of the pixel where the touch was regi stered | |
| 347 */ | |
| 348 private void initializeAnimationAndRevealView( | |
| 349 final float touchPointX, final float touchPointY) { | |
| 350 mPagerView.setVisibility(View.VISIBLE); | |
| 351 | |
| 352 int[] locationOnScreen = new int[2]; | |
| 353 mPagerView.getLocationOnScreen(locationOnScreen); | |
| 354 | |
| 355 mContextMenuLocationOnScreen = locationOnScreen[1]; | |
| 356 mPagerView.startAnimation( | |
| 357 initAnimations(touchPointX, touchPointY, locationOnScreen[0], lo cationOnScreen[1])); | |
| 358 } | |
| 359 | |
| 360 /** | |
| 361 * @param startX The starting x-coordinate of the translation animation | |
|
Theresa
2017/05/19 17:19:30
nit: add a period to the end of all param descript
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 362 * @param startY The starting y-coordinate of the translation animation | |
| 363 * @param viewLocationX The x-coordinate of the top left corner of the view relative to the | |
| 364 * device | |
| 365 * @param viewLocationY The y-coordinate of the top left corner of the view relative to the | |
| 366 * device | |
| 367 * @return Returns the animation set containing the scale & translation anim ations with the | |
| 368 * pivots set relative to the view because 0, 0 is relative to the v iew, not the device | |
| 369 * window | |
| 370 */ | |
| 371 protected Animation initAnimations(final float touchPointX, final float touc hPointY, | |
| 372 int viewLocationX, int viewLocationY) { | |
| 373 float offset = mContentViewCore.getRenderCoordinates().getContentOffsetY Pix(); | |
|
Theresa
2017/05/19 17:19:30
nit: Add a comment about why this is necessary.
I
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 374 mContextMenuSourceX = touchPointX - viewLocationX; | |
| 375 mContextMenuSourceY = touchPointY - viewLocationY + offset; | |
| 376 return getScaleAnimation(true); | |
| 377 } | |
| 378 | |
| 379 /** | |
| 266 * When an thumbnail is retrieved for the header of an image, this will set the header to | 380 * When an thumbnail is retrieved for the header of an image, this will set the header to |
| 267 * that particular bitmap. | 381 * that particular bitmap. |
| 268 */ | 382 */ |
| 269 public void onImageThumbnailRetrieved(Bitmap bitmap) { | 383 public void onImageThumbnailRetrieved(Bitmap bitmap) { |
| 270 if (mHeaderImageView != null) { | 384 if (mHeaderImageView != null) { |
| 271 mHeaderImageView.setImageBitmap(bitmap); | 385 mHeaderImageView.setImageBitmap(bitmap); |
| 272 } | 386 } |
| 273 } | 387 } |
| 274 | 388 |
| 275 @Override | 389 @Override |
| 276 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { | 390 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { |
| 277 mDialog.dismiss(); | 391 mDialog.dismiss(); |
| 278 mCallback.onResult((int) id); | 392 mCallback.onResult((int) id); |
| 279 } | 393 } |
| 394 | |
| 395 public void setContentViewCore(ContentViewCore contentViewCore) { | |
|
Theresa
2017/05/19 17:19:30
nit: JavaDoc for this public method
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 396 mContentViewCore = contentViewCore; | |
| 397 } | |
| 398 | |
| 399 private Animation getScaleAnimation(boolean comingIn) { | |
| 400 float fromX = comingIn ? 0f : 1f; | |
| 401 float toX = comingIn ? 1f : 0f; | |
| 402 float fromY = fromX; | |
| 403 float toY = toX; | |
| 404 | |
| 405 ScaleAnimation scaleAnimation = new ScaleAnimation(fromX, toX, fromY, to Y, | |
| 406 Animation.ABSOLUTE, mContextMenuSourceX, Animation.ABSOLUTE, mCo ntextMenuSourceY); | |
|
Theresa
2017/05/19 17:19:30
On dismiss, is the context menu disappearing back
Daniel Park
2017/05/22 18:12:55
The updated design asks for it to go back to the t
| |
| 407 | |
| 408 long duration = (long) (comingIn ? 250 : (250 * 0.6)); | |
|
Theresa
2017/05/19 17:19:30
These int's should be defined as "private static f
Daniel Park
2017/05/22 18:12:55
Done.
| |
| 409 scaleAnimation.setDuration(duration); | |
| 410 scaleAnimation.setInterpolator(new LinearOutSlowInInterpolator()); | |
| 411 return scaleAnimation; | |
| 412 } | |
| 280 } | 413 } |
| OLD | NEW |