读书人

关于android4.0.4中彩蛋的兑现

发布时间: 2012-11-23 00:03:43 作者: rapoo

关于android4.0.4中彩蛋的实现

情况:

在android4.0.4的系统设置-关于手机-Android版本,连续快速点击几下,就会出现一个机器人,长按住机器人不放,机器人会一直变大,然后出现一堆机器从屏幕上飞过

关于android4.0.4中彩蛋的兑现关于android4.0.4中彩蛋的兑现关于android4.0.4中彩蛋的兑现

觉得有点意思,于是想看看是怎么实现的,电脑上有android4.0的代码。

系统设置-关于手机的代码:

packages/apps/Settings/src/com/android/settings/DeviceInfoSettings.java

其中,点击选项的处理如下:

long[] mHits = new long[3];

  1. @Override
  2. public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
  3. if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) {
  4. System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
  5. mHits[mHits.length-1] = SystemClock.uptimeMillis();
  6. if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
  7. Intent intent = new Intent(Intent.ACTION_MAIN);
  8. intent.setClassName("android",
  9. com.android.internal.app.PlatLogoActivity.class.getName());
  10. try {
  11. startActivity(intent);
  12. } catch (Exception e) {
  13. Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
  14. }
  15. }
  16. }
  17. return super.onPreferenceTreeClick(preferenceScreen, preference);
  18. }
这里可以看到对固件版本选项有特殊处理:

if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) {

//如果点击的是固件版本,则记录下最近三次点击的时间;

//如果三次点击的总时间少于500ms,则启动com.android.internal.app.PlatLogoActivity

}


再看PlatLogoActivity的实现:

  1. public class PlatLogoActivity extends Activity {
  2. Toast mToast;
  3. ImageView mContent;
  4. Vibrator mZzz = new Vibrator();
  5. int mCount;
  6. final Handler mHandler = new Handler();
  7. Runnable mSuperLongPress = new Runnable() {
  8. public void run() {
  9. mCount++;
  10. mZzz.vibrate(50 * mCount);
  11. final float scale = 1f + 0.25f * mCount * mCount;
  12. mContent.setScaleX(scale);
  13. mContent.setScaleY(scale);
  14. if (mCount <= 3) {
  15. mHandler.postDelayed(mSuperLongPress, ViewConfiguration.getLongPressTimeout());
  16. } else {
  17. try {
  18. startActivity(new Intent(Intent.ACTION_MAIN)
  19. .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  20. | Intent.FLAG_ACTIVITY_CLEAR_TASK
  21. | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
  22. .setClassName("com.android.systemui","com.android.systemui.Nyandroid"));
  23. } catch (ActivityNotFoundException ex) {
  24. android.util.Log.e("PlatLogoActivity", "Couldn't find platlogo screensaver.");
  25. }
  26. finish();
  27. }
  28. }
  29. };
  30. @Override
  31. protected void onCreate(Bundle savedInstanceState) {
  32. super.onCreate(savedInstanceState);
  33. mToast = Toast.makeText(this, "Android 4.0: Ice Cream Sandwich", Toast.LENGTH_SHORT);
  34. mContent = new ImageView(this);
  35. mContent.setImageResource(com.android.internal.R.drawable.platlogo);
  36. mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
  37. mContent.setOnTouchListener(new View.OnTouchListener() {
  38. @Override
  39. public boolean onTouch(View v, MotionEvent event) {
  40. final int action = event.getAction();
  41. if (action == MotionEvent.ACTION_DOWN) {
  42. mContent.setPressed(true);
  43. mHandler.removeCallbacks(mSuperLongPress);
  44. mCount = 0;
  45. mHandler.postDelayed(mSuperLongPress, 2*ViewConfiguration.getLongPressTimeout());
  46. } else if (action == MotionEvent.ACTION_UP) {
  47. if (mContent.isPressed()) {
  48. mContent.setPressed(false);
  49. mHandler.removeCallbacks(mSuperLongPress);
  50. mToast.show();
  51. }
  52. }
  53. return true;
  54. }
  55. });
  56. setContentView(mContent);
  57. }
  58. }
这里对图片的触摸事件进行了处理,

mHandler.postDelayed(mSuperLongPress, 2*ViewConfiguration.getLongPressTimeout());

在图片按下开始,2倍长按超时时间后,执行mSuperLongPress,而在mSuperLongPress中会设置图片缩放比例,逐渐放大。图片连续放大超过三次后,启动com.android.systemui.Nyandroid,显示一堆机器人。


frameworks/base/packages/SystemUI/src/com/android/systemui/Nyandroid.java

  1. public class Nyandroid extends Activity {
  2. final static boolean DEBUG = false;
  3. public static class Board extends FrameLayout
  4. {
  5. public static final boolean FIXED_STARS = true;
  6. public static final int NUM_CATS = 20;
  7. static Random sRNG = new Random();
  8. static float lerp(float a, float b, float f) {
  9. return (b-a)*f + a;
  10. }
  11. static float randfrange(float a, float b) {
  12. return lerp(a, b, sRNG.nextFloat());
  13. }
  14. static int randsign() {
  15. return sRNG.nextBoolean() ? 1 : -1;
  16. }
  17. static <E> E pick(E[] array) {
  18. if (array.length == 0) return null;
  19. return array[sRNG.nextInt(array.length)];
  20. }
  21. public class FlyingCat extends ImageView {
  22. public static final float VMAX = 1000.0f;
  23. public static final float VMIN = 100.0f;
  24. public float v, vr;
  25. public float dist;
  26. public float z;
  27. public ComponentName component;
  28. public FlyingCat(Context context, AttributeSet as) {
  29. super(context, as);
  30. setImageResource(R.drawable.nyandroid_anim); // @@@
  31. if (DEBUG) setBackgroundColor(0x80FF0000);
  32. }
  33. public String toString() {
  34. return String.format("<cat (%.1f, %.1f) (%d x %d)>",
  35. getX(), getY(), getWidth(), getHeight());
  36. }
  37. public void reset() {
  38. final float scale = lerp(0.1f,2f,z);
  39. setScaleX(scale); setScaleY(scale);
  40. setX(-scale*getWidth()+1);
  41. setY(randfrange(0, Board.this.getHeight()-scale*getHeight()));
  42. v = lerp(VMIN, VMAX, z);
  43. dist = 0;
  44. // android.util.Log.d("Nyandroid", "reset cat: " + this);
  45. }
  46. public void update(float dt) {
  47. dist += v * dt;
  48. setX(getX() + v * dt);
  49. }
  50. }
  51. TimeAnimator mAnim;
  52. public Board(Context context, AttributeSet as) {
  53. super(context, as);
  54. setLayerType(View.LAYER_TYPE_HARDWARE, null);
  55. setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
  56. setBackgroundColor(0xFF003366);
  57. }
  58. private void reset() {
  59. // android.util.Log.d("Nyandroid", "board reset");
  60. removeAllViews();
  61. final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams(
  62. ViewGroup.LayoutParams.WRAP_CONTENT,
  63. ViewGroup.LayoutParams.WRAP_CONTENT);
  64. if (FIXED_STARS) {
  65. for(int i=0; i<20; i++) {
  66. ImageView fixedStar = new ImageView(getContext(), null);
  67. if (DEBUG) fixedStar.setBackgroundColor(0x8000FF80);
  68. fixedStar.setImageResource(R.drawable.star_anim); // @@@
  69. addView(fixedStar, wrap);
  70. final float scale = randfrange(0.1f, 1f);
  71. fixedStar.setScaleX(scale); fixedStar.setScaleY(scale);
  72. fixedStar.setX(randfrange(0, getWidth()));
  73. fixedStar.setY(randfrange(0, getHeight()));
  74. final AnimationDrawable anim = (AnimationDrawable) fixedStar.getDrawable();
  75. postDelayed(new Runnable() {
  76. public void run() {
  77. anim.start();
  78. }}, (int) randfrange(0, 1000));
  79. }
  80. }
  81. for(int i=0; i<NUM_CATS; i++) {
  82. FlyingCat nv = new FlyingCat(getContext(), null);
  83. addView(nv, wrap);
  84. nv.z = ((float)i/NUM_CATS);
  85. nv.z *= nv.z;
  86. nv.reset();
  87. nv.setX(randfrange(0,Board.this.getWidth()));
  88. final AnimationDrawable anim = (AnimationDrawable) nv.getDrawable();
  89. postDelayed(new Runnable() {
  90. public void run() {
  91. anim.start();
  92. }}, (int) randfrange(0, 1000));
  93. }
  94. if (mAnim != null) {
  95. mAnim.cancel();
  96. }
  97. mAnim = new TimeAnimator();
  98. mAnim.setTimeListener(new TimeAnimator.TimeListener() {
  99. public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
  100. // setRotation(totalTime * 0.01f); // not as cool as you would think
  101. // android.util.Log.d("Nyandroid", "t=" + totalTime);
  102. for (int i=0; i<getChildCount(); i++) {
  103. View v = getChildAt(i);
  104. if (!(v instanceof FlyingCat)) continue;
  105. FlyingCat nv = (FlyingCat) v;
  106. nv.update(deltaTime / 1000f);
  107. final float catWidth = nv.getWidth() * nv.getScaleX();
  108. final float catHeight = nv.getHeight() * nv.getScaleY();
  109. if ( nv.getX() + catWidth < -2
  110. || nv.getX() > getWidth() + 2
  111. || nv.getY() + catHeight < -2
  112. || nv.getY() > getHeight() + 2)
  113. {
  114. nv.reset();
  115. }
  116. }
  117. }
  118. });
  119. }
  120. @Override
  121. protected void onSizeChanged (int w, int h, int oldw, int oldh) {
  122. super.onSizeChanged(w,h,oldw,oldh);
  123. // android.util.Log.d("Nyandroid", "resized: " + w + "x" + h);
  124. post(new Runnable() { public void run() {
  125. reset();
  126. mAnim.start();
  127. } });
  128. }
  129. @Override
  130. protected void onDetachedFromWindow() {
  131. super.onDetachedFromWindow();
  132. mAnim.cancel();
  133. }
  134. @Override
  135. public boolean isOpaque() {
  136. return true;
  137. }
  138. }
  139. private Board mBoard;
  140. @Override
  141. public void onStart() {
  142. super.onStart();
  143. getWindow().addFlags(
  144. WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
  145. | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
  146. );
  147. }
  148. @Override
  149. public void onResume() {
  150. super.onResume();
  151. mBoard = new Board(this, null);
  152. setContentView(mBoard);
  153. mBoard.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
  154. @Override
  155. public void onSystemUiVisibilityChange(int vis) {
  156. if (0 == (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) {
  157. Nyandroid.this.finish();
  158. }
  159. }
  160. });
  161. }
  162. @Override
  163. public void onUserInteraction() {
  164. // android.util.Log.d("Nyandroid", "finishing on user interaction");
  165. finish();
  166. }
  167. }
这里面FlyingCat继承了ImageView,每次产生一个FlyingCat,生成的图片大小都是随机的。

Board继承了FrameLayout,所有的星星和机器人图片都添加到Board中。

Board使用TimeAnimator定时刷新每个机器人图片的位置,实现了移动。

星星和机器本身的变化是同过boolean postDelayed(Runnable r, long delayMillis)实现自身形状变化的。

  1. postDelayed(new Runnable() {
  2. public void run() {
  3. anim.start();
  4. }}, (int) randfrange(0, 1000));

2楼BangBangZuo4天前 13:44
哈哈,挺有意思的
1楼jindows4天前 11:49
可惜版本不是,才4.0.3 。

读书人网 >Android

热点推荐