) lineHeights.clone();
130 | this.measuredWidth = measuredWidth;
131 | }
132 |
133 | public MeasuredTextResult copy() {
134 | return new MeasuredTextResult(measuredLines, lineHeights, measuredWidth);
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/UrlCell.java:
--------------------------------------------------------------------------------
1 | package cellText;
2 |
3 | import android.content.Intent;
4 |
5 |
6 | public class UrlCell extends ColorTextCell {
7 |
8 | private static final long serialVersionUID = -7091133393080460624L;
9 |
10 | private int action;
11 |
12 | public static final int ACTION_NORMAL = 1;
13 |
14 | public static final int ACTION_GOTODETAIL = ACTION_NORMAL + 1;
15 |
16 | public UrlCell(String txt, String url,String post) {
17 | type = type & ~FLAG_TYPE_MASK | SIGN_URL;
18 | setUrl(url);
19 | text = txt;
20 | this.post = post;
21 | if (url.contains("enterdetail")) {
22 | action = ACTION_GOTODETAIL;
23 | } else {
24 | action = ACTION_NORMAL;
25 | }
26 | // text = CodePointUtils.filter(txt, DefaultCodePointFilter.g());
27 | }
28 |
29 | @Override
30 | public Intent getIntent() {
31 | Intent intent = new Intent(Intent.ACTION_VIEW);
32 | // intent.setAction(Intent.ACTION_VIEW);
33 | // boolean defaultBroswerEnable = MicroblogApp.getSelf().getSettingManager().getDefaultBroswerEnable();
34 | // if (defaultBroswerEnable) {
35 | // intent.setData(Uri.parse(Utils.formatInternalBrowserUrlWithParams(url, true, false, false)));
36 | // } else {
37 | // intent.setData(Uri.parse(Utils.formatExternalBrowserUrlWithSid(url)));
38 | // }
39 | return intent;
40 | }
41 |
42 | public int getAction() {
43 | return action;
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/UserNameCell.java:
--------------------------------------------------------------------------------
1 | package cellText;
2 |
3 |
4 | public class UserNameCell extends ColorTextCell {
5 |
6 | private static final long serialVersionUID = 90745655000732280L;
7 | public UserNameCell() {
8 | this(TextCell.SIGN_USER);
9 | }
10 |
11 | public UserNameCell(int type) {
12 | this(type, null);
13 | }
14 |
15 | public UserNameCell(int type, String text) {
16 | super(type, text);
17 | init(type, text);
18 | }
19 |
20 | private void init(int type, String text) {
21 | /*
22 | setTextColor(DLApp.getContext()
23 | .getResources().getColor(R.color.feed_user_name));
24 | */
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/touchbehavior/SingleClickBehavior.java:
--------------------------------------------------------------------------------
1 | package cellText.touchbehavior;
2 |
3 | import android.view.MotionEvent;
4 |
5 |
6 | public class SingleClickBehavior extends TouchBehavior {
7 |
8 | private static final int CLICK_AREA = TouchAnalizer.CLICK_AREA;
9 | private float lastPosX = -1, lastPosY = -1;
10 |
11 | public SingleClickBehavior(TouchAnalizer manager) {
12 | super(manager);
13 | behaviorType = TouchAnalizer.BehaviorType.SINGLE_CLICK;
14 | }
15 |
16 | private boolean checkOutside(MotionEvent curr) {
17 | if (curr == null || lastPosX == -1 || lastPosY == -1) {
18 | return true;
19 | }
20 | float dx = lastPosX - curr.getX();
21 | float dy = lastPosY - curr.getY();
22 | boolean ret = dx * dx + dy * dy > CLICK_AREA;
23 | return ret;
24 | }
25 |
26 | @Override
27 | public int analizeTouchEvent(MotionEvent event) {
28 | int ret = RET_CONTINUE;
29 | switch (event.getAction()) {
30 | case MotionEvent.ACTION_DOWN:
31 | lastPosX = event.getX();
32 | lastPosY = event.getY();
33 | if (judger != null) {
34 | ret = judger.judgeEvent(behaviorType, lastPosX, lastPosY, 0);
35 | }
36 | break;
37 | case MotionEvent.ACTION_MOVE:
38 | if (checkOutside(event)) {
39 | ret = RET_FAILED;
40 | } else {
41 | ret = RET_CONTINUE;
42 | }
43 | break;
44 | case MotionEvent.ACTION_UP:
45 | if (checkOutside(event)) {
46 | ret = RET_FAILED;
47 | } else {
48 | ret = RET_MATCHED;
49 | }
50 | break;
51 | default:
52 | ret = RET_FAILED;
53 | break;
54 | }
55 | if (ret == RET_FAILED || ret == RET_MATCHED) {
56 | lastPosX = lastPosY = -1;
57 | }
58 | return ret;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/touchbehavior/TouchAnalizer.java:
--------------------------------------------------------------------------------
1 | package cellText.touchbehavior;
2 |
3 |
4 |
5 | import android.view.MotionEvent;
6 |
7 |
8 | public class TouchAnalizer {
9 |
10 | public static class BehaviorType {
11 | public static final int SINGLE_CLICK = 0; // 必须按照顺序
12 | public static final int DOUBLE_CLICK = 1;
13 | public static final int DRAG = 2;
14 | public static final int SINGLE_DRAG = 3; // for API level 3-
15 | public static final int SLASH = 4;
16 | public static final int MULTI_SLASH = 5;
17 | public static final int LONG_CLICK = 6;
18 | public static final int ROTATE = 7;
19 |
20 | public static final int MAX_TYPE_COUNT = 8; // 记得修改最大值
21 | };
22 |
23 | // public static enum BehaviorType {
24 | // SINGLE_CLICK,
25 | // DOUBLE_CLICK,
26 | // DRAG,
27 | // SINGLE_DRAG, // for API level 3-
28 | // SLASH,
29 | // MULTI_SLASH,
30 | // LONG_CLICK,
31 | // //TRIPLE_CLICK,
32 | // PINCH,
33 | // ROTATE,
34 | // };
35 |
36 | public static int CLICK_AREA = 400;
37 | public static int CLICK_AREA_SEC = 900;
38 |
39 | private TouchBehaviorListener[] listeners = new TouchBehaviorListener[BehaviorType.MAX_TYPE_COUNT];
40 | private TouchBehavior[] analizers = new TouchBehavior[BehaviorType.MAX_TYPE_COUNT];
41 |
42 |
43 | public void setListener(int behavior, TouchBehaviorListener l) {
44 | setListener(behavior, l, null);
45 | }
46 | public void setListener(int behaviorType, TouchBehaviorListener l, TouchBehavior.TouchBehaviorEventJudger judger) {
47 | int seq = behaviorType;
48 | listeners[seq] = l;
49 | if (l == null) {
50 | analizers[seq] = null;
51 | } else {
52 | if (analizers[seq] == null) {
53 | analizers[seq] = createTouchBehavior(behaviorType);
54 | }
55 | }
56 | if (analizers[seq] != null && judger != null) {
57 | analizers[seq].setJudger(judger);
58 | }
59 | }
60 |
61 | private TouchBehavior createTouchBehavior(int behavior) {
62 | switch (behavior) {
63 | case BehaviorType.SINGLE_CLICK:
64 | return new SingleClickBehavior(this);
65 | // case DOUBLE_CLICK:
66 | // return new DoubleClickBehavior(this);
67 | // case DRAG:
68 | // return new DragBehavior(this);
69 | // case SINGLE_DRAG:
70 | // return new DragBehaviorSinglePoint(this);
71 | // case SLASH:
72 | // return new SlashBehavior(this);
73 | // case MULTI_SLASH:
74 | // return new MultiSlashBehavior(this);
75 | // case LONG_CLICK:
76 | // return new LongClickBehavior(this);
77 | // case PINCH:
78 | // return new PinchBehavior(this);
79 | // case ROTATE:
80 | // return new RotateBehavior(this);
81 | }
82 | return null;
83 | }
84 |
85 | public boolean inputTouchEvent(MotionEvent event) {
86 | boolean ret = false;
87 | for (TouchBehavior analizer : analizers) {
88 | if (analizer != null) {
89 | if (analizer.onTouchEvent(event)) {
90 | ret = true;
91 | }
92 | }
93 | }
94 | return ret;
95 | }
96 |
97 | public void pauseBehavior(int behaviorType) {
98 | if (analizers[behaviorType] != null) {
99 | analizers[behaviorType].pause();
100 | }
101 | }
102 |
103 | public boolean onBehavior(int behaviorType, float x, float y) {
104 | return onBehavior(behaviorType, x, y, -1);
105 | }
106 |
107 | public boolean onBehavior(int behaviorType, float x, float y, int state) {
108 | if (listeners[behaviorType] != null) {
109 | return listeners[behaviorType].onInvoke(behaviorType, x, y, state);
110 | } else {
111 | return false;
112 | }
113 | }
114 |
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/touchbehavior/TouchBehavior.java:
--------------------------------------------------------------------------------
1 | package cellText.touchbehavior;
2 |
3 | import android.view.MotionEvent;
4 |
5 |
6 | public abstract class TouchBehavior {
7 |
8 | public final static int RET_CONTINUE = 0;
9 | public final static int RET_CONTINUE_FORCE_MORE = 5;
10 | public final static int RET_FAILED = 1;
11 | public final static int RET_MATCHED = 2;
12 | public final static int RET_MATCHED_AND_CALLED_TRUE = 3;
13 | public final static int RET_MATCHED_AND_CALLED_FALSE = 4;
14 |
15 | protected TouchAnalizer manager;
16 | protected int behaviorType;
17 | private boolean paused = false;
18 | protected TouchBehaviorEventJudger judger;
19 |
20 | public TouchBehavior(TouchAnalizer manager) {
21 | this.manager = manager;
22 | }
23 |
24 | public void pause() {
25 | paused = true;
26 | }
27 |
28 | public void setJudger(TouchBehaviorEventJudger judger) {
29 | this.judger = judger;
30 | }
31 |
32 | public boolean onTouchEvent(MotionEvent event) {
33 | if (paused) {
34 | if (event.getAction() == MotionEvent.ACTION_DOWN) {
35 | paused = false;
36 | } else {
37 | return false;
38 | }
39 | }
40 | int ret = analizeTouchEvent(event);
41 | if (ret == RET_CONTINUE) {
42 | return false;
43 | } else if (ret == RET_FAILED) {
44 | paused = true;
45 | return false;
46 | } else if (ret == RET_MATCHED) {
47 | return manager.onBehavior(behaviorType, event.getX(), event.getY());
48 | } else if (ret == RET_MATCHED_AND_CALLED_TRUE) {
49 | return true;
50 | } else if (ret == RET_MATCHED_AND_CALLED_FALSE) {
51 | return false;
52 | } else if (ret == RET_CONTINUE_FORCE_MORE) {
53 | return true;
54 | }
55 |
56 | // will not come to this case below.
57 | paused = true;
58 | return false;
59 | }
60 |
61 | public abstract int analizeTouchEvent(MotionEvent event);
62 |
63 | public interface TouchBehaviorEventJudger {
64 | public int judgeEvent(int behaviorType, float x, float y, int state);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/cellText/touchbehavior/TouchBehaviorListener.java:
--------------------------------------------------------------------------------
1 | package cellText.touchbehavior;
2 |
3 |
4 |
5 | public interface TouchBehaviorListener {
6 | public boolean onInvoke(int behaviorType, float x, float y, int state);
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/android/grafika/gles/FlatShadedProgram.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.android.grafika.gles;
18 |
19 | import android.opengl.GLES20;
20 | import android.util.Log;
21 |
22 | import java.nio.FloatBuffer;
23 |
24 | /**
25 | * GL program and supporting functions for flat-shaded rendering.
26 | */
27 | public class FlatShadedProgram {
28 | private static final String TAG = GlUtil.TAG;
29 |
30 | private static final String VERTEX_SHADER =
31 | "uniform mat4 uMVPMatrix;" +
32 | "attribute vec4 aPosition;" +
33 | "void main() {" +
34 | " gl_Position = uMVPMatrix * aPosition;" +
35 | "}";
36 |
37 | private static final String FRAGMENT_SHADER =
38 | "precision mediump float;" +
39 | "uniform vec4 uColor;" +
40 | "void main() {" +
41 | " gl_FragColor = uColor;" +
42 | "}";
43 |
44 | // Handles to the GL program and various components of it.
45 | private int mProgramHandle = -1;
46 | private int muColorLoc = -1;
47 | private int muMVPMatrixLoc = -1;
48 | private int maPositionLoc = -1;
49 |
50 |
51 | /**
52 | * Prepares the program in the current EGL context.
53 | */
54 | public FlatShadedProgram() {
55 | mProgramHandle = GlUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
56 | if (mProgramHandle == 0) {
57 | throw new RuntimeException("Unable to create program");
58 | }
59 | Log.d(TAG, "Created program " + mProgramHandle);
60 |
61 | // get locations of attributes and uniforms
62 |
63 | maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition");
64 | GlUtil.checkLocation(maPositionLoc, "aPosition");
65 | muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix");
66 | GlUtil.checkLocation(muMVPMatrixLoc, "uMVPMatrix");
67 | muColorLoc = GLES20.glGetUniformLocation(mProgramHandle, "uColor");
68 | GlUtil.checkLocation(muColorLoc, "uColor");
69 | }
70 |
71 | /**
72 | * Releases the program.
73 | */
74 | public void release() {
75 | GLES20.glDeleteProgram(mProgramHandle);
76 | mProgramHandle = -1;
77 | }
78 |
79 | /**
80 | * Issues the draw call. Does the full setup on every call.
81 | *
82 | * @param mvpMatrix The 4x4 projection matrix.
83 | * @param color A 4-element color vector.
84 | * @param vertexBuffer Buffer with vertex data.
85 | * @param firstVertex Index of first vertex to use in vertexBuffer.
86 | * @param vertexCount Number of vertices in vertexBuffer.
87 | * @param coordsPerVertex The number of coordinates per vertex (e.g. x,y is 2).
88 | * @param vertexStride Width, in bytes, of the data for each vertex (often vertexCount *
89 | * sizeof(float)).
90 | */
91 | public void draw(float[] mvpMatrix, float[] color, FloatBuffer vertexBuffer,
92 | int firstVertex, int vertexCount, int coordsPerVertex, int vertexStride) {
93 | GlUtil.checkGlError("draw start");
94 |
95 | // Select the program.
96 | GLES20.glUseProgram(mProgramHandle);
97 | GlUtil.checkGlError("glUseProgram");
98 |
99 | // Copy the model / view / projection matrix over.
100 | GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
101 | GlUtil.checkGlError("glUniformMatrix4fv");
102 |
103 | // Copy the color vector in.
104 | GLES20.glUniform4fv(muColorLoc, 1, color, 0);
105 | GlUtil.checkGlError("glUniform4fv ");
106 |
107 | // Enable the "aPosition" vertex attribute.
108 | GLES20.glEnableVertexAttribArray(maPositionLoc);
109 | GlUtil.checkGlError("glEnableVertexAttribArray");
110 |
111 | // Connect vertexBuffer to "aPosition".
112 | GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
113 | GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
114 | GlUtil.checkGlError("glVertexAttribPointer");
115 |
116 | // Draw the rect.
117 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
118 | GlUtil.checkGlError("glDrawArrays");
119 |
120 | // Done -- disable vertex array and program.
121 | GLES20.glDisableVertexAttribArray(maPositionLoc);
122 | GLES20.glUseProgram(0);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/android/grafika/gles/FullFrameRect.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.android.grafika.gles;
18 |
19 | import android.opengl.Matrix;
20 |
21 | /**
22 | * This class essentially represents a viewport-sized sprite that will be rendered with
23 | * a texture, usually from an external source like the camera or video decoder.
24 | */
25 | public class FullFrameRect {
26 | private final Drawable2d mRectDrawable = new Drawable2d(Drawable2d.Prefab.FULL_RECTANGLE);
27 | private Texture2dProgram mProgram;
28 |
29 | /**
30 | * Prepares the object.
31 | *
32 | * @param program The program to use. FullFrameRect takes ownership, and will release
33 | * the program when no longer needed.
34 | */
35 | public FullFrameRect(Texture2dProgram program) {
36 | mProgram = program;
37 | }
38 |
39 | /**
40 | * Releases resources.
41 | *
42 | * This must be called with the appropriate EGL context current (i.e. the one that was
43 | * current when the constructor was called). If we're about to destroy the EGL context,
44 | * there's no value in having the caller make it current just to do this cleanup, so you
45 | * can pass a flag that will tell this function to skip any EGL-context-specific cleanup.
46 | */
47 | public void release(boolean doEglCleanup) {
48 | if (mProgram != null) {
49 | if (doEglCleanup) {
50 | mProgram.release();
51 | }
52 | mProgram = null;
53 | }
54 | }
55 |
56 | /**
57 | * Returns the program currently in use.
58 | */
59 | public Texture2dProgram getProgram() {
60 | return mProgram;
61 | }
62 |
63 | /**
64 | * Changes the program. The previous program will be released.
65 | *
66 | * The appropriate EGL context must be current.
67 | */
68 | public void changeProgram(Texture2dProgram program) {
69 | mProgram.release();
70 | mProgram = program;
71 | }
72 |
73 | /**
74 | * Creates a texture object suitable for use with drawFrame().
75 | */
76 | public int createTextureObject() {
77 | return mProgram.createTextureObject();
78 | }
79 |
80 | /**
81 | * Draws a viewport-filling rect, texturing it with the specified texture object.
82 | */
83 | public void drawFrame(int textureId, float[] texMatrix) {
84 | // Use the identity matrix for MVP so our 2x2 FULL_RECTANGLE covers the viewport.
85 | mProgram.draw(GlUtil.IDENTITY_MATRIX, mRectDrawable.getVertexArray(), 0,
86 | mRectDrawable.getVertexCount(), mRectDrawable.getCoordsPerVertex(),
87 | mRectDrawable.getVertexStride(),
88 | texMatrix, mRectDrawable.getTexCoordArray(), textureId,
89 | mRectDrawable.getTexCoordStride());
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/android/grafika/gles/OffscreenSurface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.android.grafika.gles;
18 |
19 | /**
20 | * Off-screen EGL surface (pbuffer).
21 | *
22 | * It's good practice to explicitly release() the surface, preferably from a "finally" block.
23 | */
24 | public class OffscreenSurface extends EglSurfaceBase {
25 | /**
26 | * Creates an off-screen surface with the specified width and height.
27 | */
28 | public OffscreenSurface(EglCore eglCore, int width, int height) {
29 | super(eglCore);
30 | createOffscreenSurface(width, height);
31 | }
32 |
33 | /**
34 | * Releases any resources associated with the surface.
35 | */
36 | public void release() {
37 | releaseEglSurface();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/android/grafika/gles/WindowSurface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.android.grafika.gles;
18 |
19 | import android.graphics.SurfaceTexture;
20 | import android.view.Surface;
21 |
22 | /**
23 | * Recordable EGL window surface.
24 | *
25 | * It's good practice to explicitly release() the surface, preferably from a "finally" block.
26 | */
27 | public class WindowSurface extends EglSurfaceBase {
28 | private Surface mSurface;
29 | private boolean mReleaseSurface;
30 |
31 | /**
32 | * Associates an EGL surface with the native window surface.
33 | *
34 | * Set releaseSurface to true if you want the Surface to be released when release() is
35 | * called. This is convenient, but can interfere with framework classes that expect to
36 | * manage the Surface themselves (e.g. if you release a SurfaceView's Surface, the
37 | * surfaceDestroyed() callback won't fire).
38 | */
39 | public WindowSurface(EglCore eglCore, Surface surface, boolean releaseSurface) {
40 | super(eglCore);
41 | createWindowSurface(surface);
42 | mSurface = surface;
43 | mReleaseSurface = releaseSurface;
44 | }
45 |
46 | /**
47 | * Associates an EGL surface with the SurfaceTexture.
48 | */
49 | public WindowSurface(EglCore eglCore, SurfaceTexture surfaceTexture) {
50 | super(eglCore);
51 | createWindowSurface(surfaceTexture);
52 | }
53 |
54 | /**
55 | * Releases any resources associated with the EGL surface (and, if configured to do so,
56 | * with the Surface as well).
57 | *
58 | * Does not require that the surface's EGL context be current.
59 | */
60 | public void release() {
61 | releaseEglSurface();
62 | if (mSurface != null) {
63 | if (mReleaseSurface) {
64 | mSurface.release();
65 | }
66 | mSurface = null;
67 | }
68 | }
69 |
70 | /**
71 | * Recreate the EGLSurface, using the new EglBase. The caller should have already
72 | * freed the old EGLSurface with releaseEglSurface().
73 | *
74 | * This is useful when we want to update the EGLSurface associated with a Surface.
75 | * For example, if we want to share with a different EGLContext, which can only
76 | * be done by tearing down and recreating the context. (That's handled by the caller;
77 | * this just creates a new EGLSurface for the Surface we were handed earlier.)
78 | *
79 | * If the previous EGLSurface isn't fully destroyed, e.g. it's still current on a
80 | * context somewhere, the create call will fail with complaints from the Surface
81 | * about already being connected.
82 | */
83 | public void recreate(EglCore newEglCore) {
84 | if (mSurface == null) {
85 | throw new RuntimeException("not yet implemented for SurfaceTexture");
86 | }
87 | mEglCore = newEglCore; // switch to new context
88 | createWindowSurface(mSurface); // create new surface
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/App.java:
--------------------------------------------------------------------------------
1 | package com.sample;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.github.anrwatchdog.ANRWatchDog;
7 | import com.sample.hotfix.dex.MultiDex;
8 | import com.sample.performance.ActivityLifeCycleTimeUseTracker;
9 | import com.sample.performance.ViewHericacy;
10 |
11 | public class App extends Application {
12 |
13 | public App() {
14 | super();
15 | }
16 |
17 | private static Context mAppContext;
18 |
19 | public static Context getContext() {
20 | return mAppContext;
21 | }
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 | mAppContext = this;
27 | new ANRWatchDog().start();
28 |
29 | ActivityLifeCycleTimeUseTracker.getInstance().start();
30 | ViewHericacy.trackViewTreeDepth(this);
31 | }
32 |
33 | @Override
34 | protected void attachBaseContext(Context base) {
35 | super.attachBaseContext(base);
36 | MultiDex.install(this, "/data/local/tmp/test.dex");
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import java.io.IOException;
7 | import java.lang.reflect.Field;
8 | import java.lang.reflect.Method;
9 |
10 | /**
11 | * Created by clarkehe on 1/19/16.
12 | * Todo:
13 | */
14 | public class BaseActivity extends Activity {
15 |
16 |
17 | @Override
18 | protected void onPause() {
19 | super.onPause();
20 |
21 | try{
22 | dumpOverdraw();
23 | }
24 | catch (Exception e){}
25 | }
26 |
27 | private void dumpOverdraw() throws IOException {
28 |
29 | try {
30 | Class> view = Class.forName("android.view.View");
31 |
32 | Method methodGetHardwareRenderer = view.getDeclaredMethod("getHardwareRenderer");
33 | methodGetHardwareRenderer.setAccessible(true);
34 | Object Gl20Renderer = methodGetHardwareRenderer.invoke(getWindow().getDecorView());
35 |
36 | if (Gl20Renderer == null) {
37 | Log.d("过度绘制测试", " 异常,Gl20Renderer为空");
38 | return;
39 | }
40 |
41 | Field fieldDebugOverdrawLayer = Gl20Renderer.getClass().getSuperclass().getDeclaredField("mDebugOverdrawLayer");
42 | fieldDebugOverdrawLayer.setAccessible(true);
43 | Object GLES20RenderLayer = fieldDebugOverdrawLayer.get(Gl20Renderer);
44 |
45 | if (GLES20RenderLayer == null) {
46 | Log.d("过度绘制测试", " 异常,GLES20RenderLayer为空");
47 | return;
48 | }
49 |
50 | Method methodGetCanvas = GLES20RenderLayer.getClass().getSuperclass().getSuperclass().getDeclaredMethod("getCanvas");
51 | methodGetCanvas.setAccessible(true);
52 | Object GLES20Canvas = methodGetCanvas.invoke(GLES20RenderLayer);
53 |
54 | Method methodGetOverdraw = Gl20Renderer.getClass().getDeclaredMethod("getOverdraw", Class.forName("android.view.HardwareCanvas"));
55 | methodGetOverdraw.setAccessible(true);
56 | Float result = (Float) methodGetOverdraw.invoke(Gl20Renderer, GLES20Canvas);
57 |
58 | String path = getClass().getPackage().getName() + "." + getClass().getSimpleName() + ".java";
59 | Log.d("过度绘制测试", "");
60 |
61 | } catch (Exception e) {
62 | Log.d("过度绘制测试", " 异常");
63 | }
64 | }
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/Fragment/MyActivtiy.java:
--------------------------------------------------------------------------------
1 | package com.sample.Fragment;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v4.app.FragmentActivity;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.Button;
11 |
12 | import com.sample.R;
13 |
14 |
15 | /**
16 | * Created by clarkehe on 3/22/16.
17 | * Todo:
18 | */
19 | public class MyActivtiy extends FragmentActivity {
20 |
21 | @Override
22 | public View onCreateView(String name, Context context, AttributeSet attrs) {
23 | return super.onCreateView(name, context, attrs);
24 | }
25 |
26 | @Override
27 | protected void onSaveInstanceState(Bundle outState) {
28 | super.onSaveInstanceState(outState);
29 | Log.d("MyActivtiy", "onSaveInstanceState");
30 | }
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.layout_fragment);
36 | }
37 |
38 | @Override
39 | protected void onStop() {
40 | super.onStop();
41 | }
42 |
43 | public MyActivtiy() {
44 | super();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/Fragment/MyFragment.java:
--------------------------------------------------------------------------------
1 | package com.sample.Fragment;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.sample.MainActivity;
12 | import com.sample.R;
13 |
14 | /**
15 | * Created by clarkehe on 3/22/16.
16 | * Todo:
17 | */
18 | public class MyFragment extends Fragment {
19 | @Override
20 | public void onAttach(Activity activity) {
21 | super.onAttach(activity);
22 | }
23 |
24 | @Override
25 | public void onDetach() {
26 | super.onDetach();
27 | }
28 |
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
31 | //return super.onCreateView(inflater, container, savedInstanceState);
32 | View view = inflater.inflate(R.layout.fragment, container, false);
33 | view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
34 | @Override
35 | public void onClick(View v) {
36 | Intent intent = new Intent(MyFragment.this.getActivity(), MainActivity.class);
37 | MyFragment.this.getActivity().startActivity(intent);
38 | }
39 | });
40 | return view;
41 | }
42 |
43 | @Override
44 | public void onViewCreated(View view, Bundle savedInstanceState) {
45 | super.onViewCreated(view, savedInstanceState);
46 | }
47 |
48 | @Override
49 | public void onStart() {
50 | super.onStart();
51 | }
52 |
53 | @Override
54 | public void onResume() {
55 | super.onResume();
56 | }
57 |
58 | @Override
59 | public void onPause() {
60 | super.onPause();
61 | }
62 |
63 | @Override
64 | public void onStop() {
65 | super.onStop();
66 | }
67 |
68 | @Override
69 | public void onDestroy() {
70 | super.onDestroy();
71 | }
72 |
73 | @Override
74 | public void onDestroyView() {
75 | super.onDestroyView();
76 | }
77 |
78 | public MyFragment() {
79 | super();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/MyLinearLayout.java:
--------------------------------------------------------------------------------
1 | package com.sample;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.LinearLayout;
6 |
7 | /**
8 | * Created by fclarke on 12/23/15.
9 | */
10 | public class MyLinearLayout extends LinearLayout{
11 |
12 | public MyLinearLayout(Context context) {
13 | super(context);
14 | }
15 |
16 | public MyLinearLayout(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | @Override
21 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
22 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
23 | }
24 |
25 | @Override
26 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
27 | super.onLayout(changed, l, t, r, b);
28 | }
29 |
30 | public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
31 | super(context, attrs, defStyleAttr);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/ScreenShotView.java:
--------------------------------------------------------------------------------
1 | package com.sample;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.view.View;
6 |
7 | /**
8 | * Created by clarkehe on 1/28/16.
9 | * Todo:
10 | */
11 | public class ScreenShotView {
12 |
13 | public Bitmap screenShot(View view) {
14 | Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
15 | Canvas canvas = new Canvas(bitmap);
16 | view.draw(canvas);
17 | return bitmap;
18 | }
19 |
20 | public Bitmap getMagicDrawingCache(View view) {
21 |
22 | Bitmap bitmap = null;//(Bitmap) view.getTag(cacheBitmapKey);
23 |
24 | if (view.getWidth() + view.getHeight() == 0) {
25 | view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
26 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
27 | }
28 |
29 | int viewWidth = view.getWidth();
30 | int viewHeight = view.getHeight();
31 | bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);
32 |
33 | bitmap.eraseColor(0xffffff);
34 | Canvas canvas = new Canvas(bitmap);
35 | view.draw(canvas);
36 |
37 | return bitmap;
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/TEST/NewTestView.java:
--------------------------------------------------------------------------------
1 | package com.sample.TEST;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 | import android.widget.ImageView;
6 |
7 | import com.sample.R;
8 |
9 | /**
10 | * Created by clarkehe on 1/14/16.
11 | * Todo:
12 | */
13 | public class NewTestView {
14 |
15 | public NewTestView(Context context)
16 | {
17 | ImageView image = new ImageView(context);
18 | image.setBackgroundResource(R.mipmap.startup_twinkle_animation4);
19 |
20 | TestView view = new TestView(context);
21 | Log.d("TAG", view.toString());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/TEST/TestView.java:
--------------------------------------------------------------------------------
1 | package com.sample.TEST;
2 |
3 | import android.content.Context;
4 | import android.widget.ImageView;
5 |
6 | import com.sample.R;
7 |
8 | /**
9 | * Created by clarkehe on 1/14/16.
10 | * Todo: TestView
11 | */
12 | public class TestView {
13 |
14 | public TestView(Context context)
15 | {
16 | ImageView image = new ImageView(context);
17 | image.setBackgroundResource(R.mipmap.startup_twinkle_animation4);
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/animator/AnimatorActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.animator;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.view.animation.OvershootInterpolator;
7 | import android.view.animation.TranslateAnimation;
8 |
9 | import com.sample.R;
10 |
11 | public class AnimatorActivity extends Activity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_animator);
17 | findViewById(R.id.startAnimator).setOnClickListener(new View.OnClickListener() {
18 | @Override
19 | public void onClick(View v) {
20 | start();
21 | }
22 | });
23 | }
24 |
25 | void start() {
26 | TranslateAnimation animation = new TranslateAnimation(500, 0, 500, 0);
27 | animation.setDuration(3000);
28 | animation.setInterpolator(new OvershootInterpolator());
29 |
30 | View view = findViewById(R.id.startAnimator);
31 | view.startAnimation(animation);
32 |
33 | try {
34 | Thread.sleep(3000);
35 | } catch (Exception e) {
36 |
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/anr/ANRTestActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.anr;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.sample.R;
8 |
9 | public class ANRTestActivity extends Activity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_anr_test);
15 |
16 | findViewById(R.id.but).setOnClickListener(new View.OnClickListener() {
17 | @Override
18 | public void onClick(View v) {
19 | try {
20 | Thread.sleep(6000);
21 | } catch (Exception e) {
22 |
23 | }
24 | }
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvc/MVCActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvc;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.View;
7 | import android.widget.EditText;
8 | import android.widget.TextView;
9 |
10 | import com.sample.R;
11 |
12 | import rx.Subscriber;
13 | import rx.android.schedulers.AndroidSchedulers;
14 |
15 | //MVCActivity相当于MVC中的Control.
16 |
17 | public class MVCActivity extends Activity {
18 |
19 | private EditText cityNOInput;
20 | private TextView city;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_mvc);
26 | initView();
27 | }
28 |
29 | //初始化View
30 | private void initView() {
31 | cityNOInput = (EditText) findViewById(R.id.zoneId);
32 | city = (TextView) findViewById(R.id.info);
33 |
34 | findViewById(R.id.go).setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | //Control call model
38 | getWeather(cityNOInput.getText().toString().trim());
39 | }
40 | });
41 | }
42 |
43 | private void getWeather(String cityNumber) {
44 | //Model
45 | new Model().getWeather(cityNumber)
46 | .observeOn(AndroidSchedulers.mainThread())
47 | .subscribe(new Subscriber() {
48 | @Override
49 | public void onCompleted() {
50 | }
51 |
52 | @Override
53 | public void onError(Throwable e) {
54 | }
55 |
56 | @Override
57 | public void onNext(String result) {
58 | Log.d("TAG", "result:" + result);
59 | //Model notify control
60 | updateView(result);
61 | }
62 | });
63 | }
64 |
65 | //control update view
66 | private void updateView(final String result) {
67 | city.setText(result);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvc/Model.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvc;
2 |
3 | import com.kymjs.rxvolley.RxVolley;
4 | import com.kymjs.rxvolley.rx.Result;
5 |
6 | import rx.Observable;
7 | import rx.functions.Func1;
8 |
9 | public class Model {
10 |
11 | Observable getWeather(final String cityNumber) {
12 |
13 | Observable observable = new RxVolley.Builder()
14 | .url("http://www.weather.com.cn/data/sk/" + cityNumber + ".html")
15 | .contentType(RxVolley.ContentType.JSON)
16 | .getResult();
17 |
18 | return observable.map(new Func1() {
19 | @Override
20 | public String call(Result result) {
21 | return new String(result.data);
22 | }
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvp/model/IModel.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvp.model;
2 |
3 | import rx.Observable;
4 |
5 | public interface IModel {
6 | Observable getWeather(final String cityNumber);
7 | }
8 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvp/model/Model.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvp.model;
2 |
3 | import com.kymjs.rxvolley.RxVolley;
4 | import com.kymjs.rxvolley.rx.Result;
5 |
6 | import rx.Observable;
7 | import rx.functions.Func1;
8 |
9 | public class Model implements IModel {
10 |
11 | @Override
12 | public Observable getWeather(final String cityNumber) {
13 |
14 | Observable observable = new RxVolley.Builder()
15 | .url("http://www.weather.com.cn/data/sk/" + cityNumber + ".html")
16 | .contentType(RxVolley.ContentType.JSON)
17 | .getResult();
18 |
19 | return observable.map(new Func1() {
20 | @Override
21 | public String call(Result result) {
22 | return new String(result.data);
23 | }
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvp/presenter/Presenter.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvp.presenter;
2 |
3 | import android.util.Log;
4 |
5 | import com.sample.architect.mvp.model.IModel;
6 | import com.sample.architect.mvp.model.Model;
7 | import com.sample.architect.mvp.view.IView;
8 |
9 | import rx.Subscriber;
10 | import rx.android.schedulers.AndroidSchedulers;
11 |
12 | //P也不直接引用VIEW,而是VIEW的接口。
13 | //定义VIEW的接口也比较麻烦,也可让P直接引用VIEW,这样VM还是可能还是有耦合,但达到了简化了C的目的,有点像VIEW-CONTROL或子的MVC
14 |
15 | public class Presenter {
16 |
17 | private IView mView;
18 | private IModel mMode;
19 |
20 | public Presenter(final IView view) {
21 | mView = view;
22 | mMode = new Model();
23 | }
24 |
25 | public void updateInfo(final String cityNumber) {
26 | //Model
27 | mMode.getWeather(cityNumber)
28 | .observeOn(AndroidSchedulers.mainThread())
29 | .subscribe(new Subscriber() {
30 | @Override
31 | public void onCompleted() {
32 | }
33 |
34 | @Override
35 | public void onError(Throwable e) {
36 | }
37 |
38 | @Override
39 | public void onNext(String result) {
40 | Log.d("TAG", "result:" + result);
41 | //update view
42 | mView.updateView(result);
43 | }
44 | });
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvp/view/IView.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvp.view;
2 |
3 | public interface IView {
4 | void updateView(final String info);
5 | }
6 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/architect/mvp/view/MVPActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.architect.mvp.view;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.EditText;
7 | import android.widget.TextView;
8 |
9 | import com.sample.R;
10 | import com.sample.architect.mvp.presenter.Presenter;
11 |
12 | //MVP, 有一部分工作交给了P,MVC中原来的C简单了。
13 | //同时,M与V进一步解耦,V感受不M的存在,是隔离的。
14 |
15 | public class MVPActivity extends Activity implements IView {
16 |
17 | private EditText cityNOInput;
18 | private TextView city;
19 |
20 | private Presenter mPresenter;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_mvp);
26 | initView();
27 |
28 | //Presenter
29 | mPresenter = new Presenter(this);
30 | }
31 |
32 | //初始化View
33 | private void initView() {
34 | cityNOInput = (EditText) findViewById(R.id.zoneId);
35 | city = (TextView) findViewById(R.id.info);
36 |
37 | findViewById(R.id.go).setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | //Use Presenter
41 | getWeather(cityNOInput.getText().toString().trim());
42 | }
43 | });
44 | }
45 |
46 | private void getWeather(String cityNumber) {
47 | //Presenter
48 | mPresenter.updateInfo(cityNumber);
49 | }
50 |
51 | @Override
52 | public void updateView(String info) {
53 | city.setText(info);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/attr_style/AttrStyleActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.attr_style;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | import com.sample.R;
7 |
8 | public class AttrStyleActivity extends Activity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_attr_style);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/attr_style/CustomView.java:
--------------------------------------------------------------------------------
1 | package com.sample.attr_style;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.View;
8 |
9 | import com.sample.R;
10 |
11 | /**
12 | * Created by clarkehe on 13/7/16.
13 | */
14 | public class CustomView extends View {
15 |
16 | private final static String TAG = "CustomView";
17 |
18 | public CustomView(Context context) {
19 | this(context, null);
20 | }
21 |
22 | public CustomView(Context context, AttributeSet attrs) {
23 | this(context, attrs, R.attr.theme_style);
24 | }
25 |
26 | public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
27 | super(context, attrs, defStyleAttr);
28 |
29 | final TypedArray a = context.obtainStyledAttributes(
30 | attrs, R.styleable.custom_attrs, defStyleAttr, R.style.default_style);
31 |
32 | String one = a.getString(R.styleable.custom_attrs_custom_attr1);
33 | String two = a.getString(R.styleable.custom_attrs_custom_attr2);
34 |
35 | Log.d(TAG, "one:" + one);
36 | Log.d(TAG, "two:" + two);
37 |
38 | a.recycle();
39 | }
40 | }
41 |
42 | /**
43 | * 有那些属性:
44 | *
45 | * 属性值的来源:
46 | * 1. AttributeSet, 来自XML指定属性及style
47 | *
48 | * set , 0 , 0 : xm1 xml2
49 | * set, x , 0 : set 没有 theme1, xml2
50 | * set, x, x
51 | */
52 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/audio/AudioActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.audio;
2 |
3 | import android.os.Bundle;
4 | import android.app.Activity;
5 | import android.os.Handler;
6 | import android.view.View;
7 |
8 | import com.sample.R;
9 |
10 | public class AudioActivity extends Activity {
11 |
12 | PlaySound playSound;
13 | Handler mHandler = new Handler();
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_audio);
19 |
20 | findViewById(R.id.frontBut).setOnClickListener(new View.OnClickListener() {
21 | @Override
22 | public void onClick(View v) {
23 | play(0, 0);
24 | }
25 | });
26 |
27 | findViewById(R.id.rightBut).setOnClickListener(new View.OnClickListener() {
28 | @Override
29 | public void onClick(View v) {
30 | play(90, 0);
31 | }
32 | });
33 |
34 | findViewById(R.id.backBut).setOnClickListener(new View.OnClickListener() {
35 | @Override
36 | public void onClick(View v) {
37 | play(0, 180);
38 | }
39 | });
40 | }
41 |
42 | float x, y, z;
43 | float t = 0;
44 |
45 | private void play(final float azimuth, final float elevation) {
46 | new Thread(new Runnable() {
47 | @Override
48 | public void run() {
49 | playSound = new PlaySound(AudioActivity.this);
50 | playSound.setPos(azimuth, elevation);
51 | playSound.play();
52 | }
53 | }).start();
54 |
55 | postDelay();
56 | }
57 |
58 | void postDelay() {
59 | mHandler.postDelayed(new Runnable() {
60 | @Override
61 | public void run() {
62 | setPost();
63 | }
64 | }, 50);
65 | }
66 |
67 | void setPost() {
68 | x = (float) Math.sin(t);
69 | y = (float) Math.cos(t);
70 | z = 0;
71 | t += 0.05;
72 |
73 | float[] ret = IR.cartesianToInteraural(x, y, z);
74 | if (playSound != null) {
75 | playSound.setPos(ret[1], ret[2]);
76 | }
77 |
78 | postDelay();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/audio/Convolve.java:
--------------------------------------------------------------------------------
1 | package com.sample.audio;
2 |
3 | /**
4 | * step 4: HRTF convolution 卷积变换
5 | *
6 | * http://www.digenis.co.uk/?p=81
7 | *
8 | * https://github.com/krruzic/convolver/blob/master/src/convolve.c
9 | */
10 |
11 | public class Convolve {
12 |
13 | static void Convolve(short[] input,
14 | int inputLength,
15 | float[] filter,
16 | int filterLength,
17 | short[] output) {
18 | // int lengthOfOutput = inputLength + filterLength - 1;
19 |
20 | // for(int i = 0; i < lengthOfOutput; ++i) {
21 | // output[i] = 0;
22 | // }
23 |
24 | for (int i = 0; i < inputLength; ++i) {
25 | for (int j = 0; j < filterLength; ++j) {
26 | output[i + j] += input[i] * filter[j];
27 | }
28 | }
29 |
30 | /*
31 | int lengthOfOutput = inputLength;
32 | for(int i = 0; i < lengthOfOutput; ++i)
33 | {
34 | output[i] = 0;
35 |
36 | for(int j=0; j getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException {
47 | ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
48 | File sourceApk = new File(applicationInfo.sourceDir);
49 | File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);
50 |
51 | List sourcePaths = new ArrayList();
52 | sourcePaths.add(applicationInfo.sourceDir); //add the default apk path
53 |
54 | //the prefix of extracted file, ie: test.classes
55 | String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
56 | //the total dex numbers
57 | int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1);
58 |
59 | for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
60 | //for each dex file, ie: test.classes2.zip, test.classes3.zip...
61 | String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
62 | File extractedFile = new File(dexDir, fileName);
63 | if (extractedFile.isFile()) {
64 | sourcePaths.add(extractedFile.getAbsolutePath());
65 | //we ignore the verify zip part
66 | } else {
67 | throw new IOException("Missing extracted secondary dex file '" +
68 | extractedFile.getPath() + "'");
69 | }
70 | }
71 |
72 | return sourcePaths;
73 | }
74 |
75 | /**
76 | * get all the classes name in "classes.dex", "classes2.dex", ....
77 | *
78 | * @param context the application context
79 | * @return all the classes name
80 | * @throws PackageManager.NameNotFoundException
81 | * @throws IOException
82 | */
83 | public static List getAllClasses(Context context) throws PackageManager.NameNotFoundException, IOException {
84 | List classNames = new ArrayList();
85 | for (String path : getSourcePaths(context)) {
86 | try {
87 | DexFile dexfile = null;
88 | if (path.endsWith(EXTRACTED_SUFFIX)) {
89 | //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
90 | dexfile = DexFile.loadDex(path, path + ".tmp", 0);
91 | } else {
92 | dexfile = new DexFile(path);
93 | }
94 | Enumeration dexEntries = dexfile.entries();
95 | while (dexEntries.hasMoreElements()) {
96 | classNames.add(dexEntries.nextElement());
97 | }
98 | } catch (IOException e) {
99 | throw new IOException("Error at loading dex file '" +
100 | path + "'");
101 | }
102 | }
103 | return classNames;
104 | }
105 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/classLoader/getgameapp/ZipUtil.java:
--------------------------------------------------------------------------------
1 | package com.sample.classLoader.getgameapp;
2 |
3 | /*
4 | * Licensed to the Apache Software Foundation (ASF) under one or more
5 | * contributor license agreements. See the NOTICE file distributed with
6 | * this work for additional information regarding copyright ownership.
7 | * The ASF licenses this file to You under the Apache License, Version 2.0
8 | * (the "License"); you may not use this file except in compliance with
9 | * the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | /* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and
20 | * ZipConstants from android libcore.
21 | */
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.io.RandomAccessFile;
26 | import java.util.zip.CRC32;
27 | import java.util.zip.ZipException;
28 |
29 | /**
30 | * Tools to build a quick partial crc of zip files.
31 | */
32 | final class ZipUtil {
33 | static class CentralDirectory {
34 | long offset;
35 | long size;
36 | }
37 |
38 | /* redefine those constant here because of bug 13721174 preventing to compile using the
39 | * constants defined in ZipFile */
40 | private static final int ENDHDR = 22;
41 | private static final int ENDSIG = 0x6054b50;
42 |
43 | /**
44 | * Size of reading buffers.
45 | */
46 | private static final int BUFFER_SIZE = 0x4000;
47 |
48 | /**
49 | * Compute crc32 of the central directory of an apk. The central directory contains
50 | * the crc32 of each entries in the zip so the computed result is considered valid for the whole
51 | * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does
52 | * not either.
53 | */
54 | static long getZipCrc(File apk) throws IOException {
55 | RandomAccessFile raf = new RandomAccessFile(apk, "r");
56 | try {
57 | CentralDirectory dir = findCentralDirectory(raf);
58 |
59 | return computeCrcOfCentralDir(raf, dir);
60 | } finally {
61 | raf.close();
62 | }
63 | }
64 |
65 | /* Package visible for testing */
66 | static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException,
67 | ZipException {
68 | long scanOffset = raf.length() - ENDHDR;
69 | if (scanOffset < 0) {
70 | throw new ZipException("File too short to be a zip file: " + raf.length());
71 | }
72 |
73 | long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */;
74 | if (stopOffset < 0) {
75 | stopOffset = 0;
76 | }
77 |
78 | int endSig = Integer.reverseBytes(ENDSIG);
79 | while (true) {
80 | raf.seek(scanOffset);
81 | if (raf.readInt() == endSig) {
82 | break;
83 | }
84 |
85 | scanOffset--;
86 | if (scanOffset < stopOffset) {
87 | throw new ZipException("End Of Central Directory signature not found");
88 | }
89 | }
90 |
91 | // Read the End Of Central Directory. ENDHDR includes the signature
92 | // bytes,
93 | // which we've already read.
94 |
95 | // Pull out the information we need.
96 | raf.skipBytes(2); // diskNumber
97 | raf.skipBytes(2); // diskWithCentralDir
98 | raf.skipBytes(2); // numEntries
99 | raf.skipBytes(2); // totalNumEntries
100 | CentralDirectory dir = new CentralDirectory();
101 | dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
102 | dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
103 | return dir;
104 | }
105 |
106 | /* Package visible for testing */
107 | static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir)
108 | throws IOException {
109 | CRC32 crc = new CRC32();
110 | long stillToRead = dir.size;
111 | raf.seek(dir.offset);
112 | int length = (int) Math.min(BUFFER_SIZE, stillToRead);
113 | byte[] buffer = new byte[BUFFER_SIZE];
114 | length = raf.read(buffer, 0, length);
115 | while (length != -1) {
116 | crc.update(buffer, 0, length);
117 | stillToRead -= length;
118 | if (stillToRead == 0) {
119 | break;
120 | }
121 | length = (int) Math.min(BUFFER_SIZE, stillToRead);
122 | length = raf.read(buffer, 0, length);
123 | }
124 | return crc.getValue();
125 | }
126 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/crashreport/CatchCrash.java:
--------------------------------------------------------------------------------
1 | package com.sample.crashreport;
2 |
3 | import android.util.Log;
4 |
5 | public class CatchCrash {
6 | private final static String TAG = "CatchCrash";
7 | private static Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
8 |
9 | public static void catchUnhandledException() {
10 | defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
11 | Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler());
12 | }
13 |
14 | private static class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
15 | @Override
16 | public void uncaughtException(Thread thread, Throwable ex) {
17 | Log.e(TAG, "***-------------");
18 | ex.printStackTrace();
19 | Log.e(TAG, "uncaughtException, thread:" + thread.getName() + ", ex:" + ex.toString());
20 | Log.e(TAG, "***-------------");
21 | defaultUncaughtExceptionHandler.uncaughtException(thread, ex);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/crashreport/TestCrashActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.crashreport;
2 |
3 | import android.os.Bundle;
4 | import android.app.Activity;
5 | import android.util.Log;
6 | import android.view.View;
7 |
8 | import com.sample.R;
9 |
10 | public class TestCrashActivity extends Activity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_test_crash);
16 |
17 | findViewById(R.id.catchCrashBut).setOnClickListener(new View.OnClickListener() {
18 | @Override
19 | public void onClick(View v) {
20 | CatchCrash.catchUnhandledException();
21 | }
22 | });
23 |
24 | findViewById(R.id.makeCrashBut).setOnClickListener(new View.OnClickListener() {
25 | @Override
26 | public void onClick(View v) {
27 | Thread thread = new Thread(new Runnable() {
28 | @Override
29 | public void run() {
30 | String test = null;
31 | Log.d("test", "" + test.length());
32 | }
33 | });
34 |
35 | thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
36 | @Override
37 | public void uncaughtException(Thread thread, Throwable ex) {
38 | Log.d("TEST", "private: uncaughtException");
39 | }
40 | });
41 |
42 | thread.start();
43 | }
44 | });
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/dialog/CustomDialog.java:
--------------------------------------------------------------------------------
1 | package com.sample.dialog;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.sample.R;
8 |
9 | public class CustomDialog extends Dialog {
10 |
11 | public CustomDialog(Context context) {
12 | super(context);
13 | }
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.custom_dialog);
19 | this.setTitle("Title");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/dialog/DialogActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.dialog;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.sample.R;
8 |
9 | public class DialogActivity extends Activity {
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_dialog);
14 |
15 | findViewById(R.id.butShowDialog).setOnClickListener(new View.OnClickListener() {
16 | @Override
17 | public void onClick(View v) {
18 | showNormalDialog();
19 | }
20 | });
21 | }
22 |
23 | private void showNormalDialog() {
24 | CustomDialog dialog = new CustomDialog(this);
25 | dialog.show();
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/glide/CustomCachingGlideModule.java:
--------------------------------------------------------------------------------
1 | package com.sample.glide;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.util.Log;
6 |
7 | import com.bumptech.glide.Glide;
8 | import com.bumptech.glide.GlideBuilder;
9 | import com.bumptech.glide.load.data.DataFetcher;
10 | import com.bumptech.glide.load.engine.cache.MemorySizeCalculator;
11 | import com.bumptech.glide.load.model.GenericLoaderFactory;
12 | import com.bumptech.glide.load.model.ModelLoader;
13 | import com.bumptech.glide.load.model.ModelLoaderFactory;
14 | import com.bumptech.glide.load.model.StringLoader;
15 | import com.bumptech.glide.load.model.stream.StreamModelLoader;
16 | import com.bumptech.glide.module.GlideModule;
17 |
18 | import java.io.InputStream;
19 |
20 | public class CustomCachingGlideModule implements GlideModule {
21 |
22 | private final static String TAG = "GlideModule|Glide";
23 |
24 | @Override
25 | public void applyOptions(Context context, GlideBuilder builder) {
26 | MemorySizeCalculator calculator = new MemorySizeCalculator(context);
27 | int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
28 | int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
29 |
30 | Log.d(TAG, "defaultMemoryCacheSize:" + defaultMemoryCacheSize);
31 | Log.d(TAG, "defaultBitmapPoolSize:" + defaultBitmapPoolSize);
32 |
33 | //int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
34 | //int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
35 |
36 | //defaultMemoryCacheSize = 0;
37 | builder.setMemoryCache(new CustomLruResourceCache(defaultMemoryCacheSize));
38 | builder.setBitmapPool(new CustomLruBitmapPool(defaultBitmapPoolSize));
39 | }
40 |
41 | @Override
42 | public void registerComponents(Context context, Glide glide) {
43 | glide.register(String.class, InputStream.class, new CustomImageSizeModelFactory());
44 | }
45 |
46 | private class CustomImageSizeUrlLoader extends StringLoader implements StreamModelLoader {
47 | @Override
48 | public DataFetcher getResourceFetcher(String model, int width, int height) {
49 | Log.d(TAG, "mode:" + model);
50 | Log.d(TAG, "width:" + width + ",height:" + height);
51 | return super.getResourceFetcher(model, width, height);
52 | }
53 |
54 | public CustomImageSizeUrlLoader(ModelLoader uriLoader) {
55 | super(uriLoader);
56 | }
57 | }
58 |
59 | private class CustomImageSizeModelFactory implements ModelLoaderFactory {
60 | @Override
61 | public ModelLoader build(Context context, GenericLoaderFactory factories) {
62 | return new CustomImageSizeUrlLoader(factories.buildModelLoader(Uri.class, InputStream.class));
63 | }
64 |
65 | @Override
66 | public void teardown() {
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/glide/CustomLruBitmapPool.java:
--------------------------------------------------------------------------------
1 | package com.sample.glide;
2 |
3 | import android.graphics.Bitmap;
4 | import android.util.Log;
5 |
6 | import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;
7 |
8 | public class CustomLruBitmapPool extends LruBitmapPool {
9 |
10 | private final static String TAG = "BitmapPool|Glide";
11 |
12 | private volatile int hitCount;
13 | private volatile int missCount;
14 |
15 | public CustomLruBitmapPool(int maxSize) {
16 | super(maxSize);
17 | }
18 |
19 | @Override
20 | public synchronized Bitmap get(int width, int height, Bitmap.Config config) {
21 | Log.d(TAG, "get, width:" + width + ",height:" + height);
22 | final Bitmap bmp = super.get(width, height, config);
23 | if (bmp != null) {
24 | hitCount += 1;
25 | } else {
26 | missCount += 1;
27 | }
28 | Log.d(TAG, "get:missCount:" + missCount + ",hitCount:" + hitCount);
29 | return bmp;
30 | }
31 |
32 | @Override
33 | public synchronized boolean put(Bitmap bitmap) {
34 | final int width = bitmap.getWidth();
35 | final int height = bitmap.getHeight();
36 | Log.d(TAG, "put, width:" + width + ",height:" + height);
37 | return super.put(bitmap);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/glide/CustomLruResourceCache.java:
--------------------------------------------------------------------------------
1 | package com.sample.glide;
2 |
3 | import android.util.Log;
4 |
5 | import com.bumptech.glide.load.Key;
6 | import com.bumptech.glide.load.engine.Resource;
7 | import com.bumptech.glide.load.engine.cache.LruResourceCache;
8 |
9 | public class CustomLruResourceCache extends LruResourceCache {
10 |
11 | private final static String TAG = "ResourceCache|Glide";
12 |
13 | private volatile int hitCount;
14 | private volatile int missCount;
15 |
16 | public CustomLruResourceCache(int size) {
17 | super(size);
18 | }
19 |
20 | @Override
21 | public Resource> put(Key key, Resource> item) {
22 | Log.d(TAG, "put");
23 | return super.put(key, item);
24 | }
25 |
26 | @Override
27 | public Resource> get(Key key) {
28 | Log.d(TAG, "get");
29 | return super.get(key);
30 | }
31 |
32 | @Override
33 | public boolean contains(Key key) {
34 | Log.d(TAG, "contains");
35 | return super.contains(key);
36 | }
37 |
38 | @Override
39 | public Resource> remove(Key key) {
40 | final Resource> item = super.remove(key);
41 | if (item == null) {
42 | missCount += 1;
43 | } else {
44 | hitCount += 1;
45 | }
46 | Log.d(TAG, "remove:missCount:" + missCount + ",hitCount:" + hitCount);
47 | return item;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/glide/GlideActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.glide;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.drawable.Drawable;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.widget.ImageView;
12 | import android.widget.TextView;
13 |
14 | import com.bumptech.glide.Glide;
15 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
16 | import com.bumptech.glide.request.animation.GlideAnimation;
17 | import com.bumptech.glide.request.target.SimpleTarget;
18 | import com.sample.R;
19 |
20 | // 源图片大小,
21 | // TARGET大小,确定TARGET大小
22 | // 缩放
23 |
24 | // ImageView又有转换(fitcenter, centercrop)
25 | // DECODE
26 |
27 | public class GlideActivity extends Activity {
28 |
29 | private final static String TAG = "GlideActivity|Glide";
30 |
31 | //980x500
32 | final String url = "http://ossweb-img.qq.com/images/lol/web201310/skin/big222000.jpg";
33 |
34 | //100x100
35 | final String url2 = "http://q3.qlogo.cn/g?b=qq&k=tysUcdic0LwrPOIK3PeWic3w&s=100&t=1457753232";
36 |
37 | final String url3 = "http://p.qpic.cn/qqtalk_snapshot/2123176/1468914847796807/320";
38 |
39 | final String url4 = "http://p.qpic.cn/qtlol/0/b9aa30750469afc192102c090effc820T1468585088986699/420";
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_glide);
45 | bindView();
46 | }
47 |
48 | private void bindView() {
49 | float dimen_10 = getResources().getDimension(R.dimen.dimen_10);
50 | Log.d(TAG, "dimen_10:" + dimen_10);
51 |
52 | final ImageView imageView = (ImageView) findViewById(R.id.imageView);
53 | Glide.with(this).load(url).transform(new GlideCircleTransform(this)).diskCacheStrategy(DiskCacheStrategy.SOURCE)
54 | .into(imageView);
55 |
56 | findViewById(R.id.but).setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | final ImageView imageView2 = (ImageView) findViewById(R.id.imageView2);
60 | Glide.with(GlideActivity.this).load(url).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView2);
61 | }
62 | });
63 |
64 | // new Handler().postDelayed(new Runnable() {
65 | // @Override
66 | // public void run() {
67 | // Drawable drawable = imageView.getDrawable();
68 | // if (drawable != null) {
69 | // final int width1 = drawable.getIntrinsicWidth();
70 | // final int height1 = drawable.getIntrinsicHeight();
71 | // Log.d(TAG, "width1:" + width1);
72 | // Log.d(TAG, "height1:" + height1);
73 | // }
74 | // }
75 | // }, 3000);
76 |
77 | //loadImage(this, url, null, -1, -1);
78 | }
79 |
80 | public static void loadImage(Context context, String url, final TextView tv, final int w, final int h) {
81 | try {
82 | Glide.with(context).load(url).asBitmap().dontAnimate().override(100, 200)
83 | .placeholder(R.drawable.ic_launcher).into(new SimpleTarget() {
84 | @Override
85 | public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
86 |
87 | final int width = resource.getWidth();
88 | final int height = resource.getHeight();
89 | Log.d(TAG, "width:" + width);
90 | Log.d(TAG, "height:" + height);
91 |
92 | if (w > 0 && h > 0) {
93 |
94 | // resource = scaleBitmap(resource, w, h);//Glide的override方法仅适用于ImageView
95 | }
96 | // TabWidgetHelper.setViewIcon(ApplicationContextHolder.getAppContext(), tv, resource, TabWidgetHelper.DrawableOrientation.TOP, false);
97 | }
98 | });
99 | } catch (IllegalArgumentException | IllegalStateException e) {
100 | e.printStackTrace();
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/glide/GlideCircleTransform.java:
--------------------------------------------------------------------------------
1 | package com.sample.glide;
2 |
3 |
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapShader;
7 | import android.graphics.Canvas;
8 | import android.graphics.Paint;
9 |
10 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
11 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
12 |
13 | //内存缓存,是缓存转换后的
14 | //磁盘缓存:SOURCE RESULT
15 |
16 | public class GlideCircleTransform extends BitmapTransformation {
17 |
18 | public GlideCircleTransform(Context context) {
19 | super(context);
20 | }
21 |
22 | @Override
23 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
24 | return circleCrop(pool, toTransform);
25 | }
26 |
27 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
28 | if (source == null) return null;
29 |
30 | int size = Math.min(source.getWidth(), source.getHeight());
31 | int x = (source.getWidth() - size) / 2;
32 | int y = (source.getHeight() - size) / 2;
33 |
34 | final Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
35 |
36 | Bitmap result = pool.get(size, size, Bitmap.Config.RGB_565);
37 | if (result == null) {
38 | result = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
39 | }
40 |
41 | Canvas canvas = new Canvas(result);
42 | Paint paint = new Paint();
43 | paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
44 | paint.setAntiAlias(true);
45 | float r = size / 2f;
46 | canvas.drawCircle(r, r, r, paint);
47 | return result;
48 | }
49 |
50 | @Override
51 | public String getId() {
52 | return getClass().getName();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/hotfix/dex/BugClass.java:
--------------------------------------------------------------------------------
1 | package com.sample.hotfix.dex;
2 |
3 | public class BugClass {
4 |
5 | String getStr() {
6 | return "Bug Class";
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/hotfix/dex/HotFixActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.hotfix.dex;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.widget.TextView;
7 |
8 | import com.sample.R;
9 |
10 | /**
11 | * 在虚拟机启动的时候,当verify选项被打开的时候,如果static方法、private方法、构造函数等,
12 | * 其中的直接引用(第一层关系)到的类都在同一个dex文件中,那么该类就会被打上CLASS_ISPREVERIFIED标志。
13 | *
14 | * 打上这个标识的作用:跟类优化有关???
15 | */
16 | public class HotFixActivity extends Activity {
17 |
18 | private final static String TAG = "HotFixActivity";
19 |
20 | /**
21 | * 08-15 16:16:36.269 4276-4276/? W/dalvikvm: Class resolved by unexpected DEX: Lcom/sample/hotfix/dex/HotFixActivity;(0x42691000):0x751cc000 ref [Lcom/sample/hotfix/dex/BugClass;] Lcom/sample/hotfix/dex/BugClass;(0x42691000):0x7505c000
22 | * 08-15 16:16:36.269 4276-4276/? W/dalvikvm: (Lcom/sample/hotfix/dex/HotFixActivity; had used a different Lcom/sample/hotfix/dex/BugClass; during pre-verification)
23 | *
24 | * 08-15 16:16:36.269 4276-4276/? E/AndroidRuntime: FATAL EXCEPTION: main
25 | * Process: com.sample, PID: 4276
26 | * java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
27 | * at com.sample.hotfix.dex.HotFixActivity.onCreate(HotFixActivity.java:20)
28 | * at android.app.Activity.performCreate(Activity.java:5231)
29 | *
30 | * 希望BugClass这个类与HotFixActivity,应该是在一个DEX文件,
31 | */
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | printClassLoad();
36 | setContentView(R.layout.activity_hot_fix);
37 | TextView view = (TextView) findViewById(R.id.textView);
38 | view.setText(new BugClass().getStr());
39 | }
40 |
41 |
42 | /**
43 | * 08-15 16:16:36.259 4276-4276/? I/HotFixActivity: [onCreate] classLoader 1 : dalvik.system.PathClassLoader[DexPathList[[dex file "dalvik.system.DexFile@426939b0", zip file "/data/app/com.sample-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.sample-1, /vendor/lib, /system/lib]]]
44 | * 08-15 16:16:36.259 4276-4276/? I/HotFixActivity: [onCreate] classLoader 1 : java.lang.BootClassLoader@41636fd0
45 | */
46 |
47 | void printClassLoad() {
48 | ClassLoader classLoader = getClassLoader();
49 | int i = 1;
50 | if (classLoader != null) {
51 | Log.i(TAG, "[onCreate] classLoader " + i + " : " + classLoader.toString());
52 |
53 | while (classLoader.getParent() != null) {
54 | classLoader = classLoader.getParent();
55 | Log.i(TAG, "[onCreate] classLoader " + i + " : " + classLoader.toString());
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/lifecycle/ActivityA.java:
--------------------------------------------------------------------------------
1 | package com.sample.lifecycle;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.Button;
8 |
9 | public class ActivityA extends Activity{
10 |
11 | public ActivityA() {
12 | super();
13 | }
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | Button button = new Button(this);
19 | button.setText("Start Activity B");
20 | this.setContentView(button);
21 |
22 | button.setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | Intent intent = new Intent(ActivityA.this, ActivityB.class);
26 | ActivityA.this.startActivity(intent);
27 | }
28 | });
29 | }
30 |
31 | static {
32 | RegActivityLifecycleCallback.regLifeCycleCallBack();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/lifecycle/ActivityB.java:
--------------------------------------------------------------------------------
1 | package com.sample.lifecycle;
2 |
3 | import android.app.Activity;
4 |
5 | public class ActivityB extends Activity{
6 |
7 | public ActivityB() {
8 | super();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/lifecycle/RegActivityLifecycleCallback.java:
--------------------------------------------------------------------------------
1 | package com.sample.lifecycle;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 |
8 | import com.sample.App;
9 |
10 | public class RegActivityLifecycleCallback {
11 |
12 | private final static String TAG = "RegActivityLifeCallback";
13 |
14 | static public void regLifeCycleCallBack()
15 | {
16 | Log.d(TAG, "regLifeCycleCallBack");
17 |
18 | final Application app = (Application) App.getContext();
19 | app.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
20 | @Override
21 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
22 | Log.d(TAG, "onActivityCreated, " + activity);
23 | }
24 |
25 | @Override
26 | public void onActivityStarted(Activity activity) {
27 | Log.d(TAG, "onActivityStarted, " + activity);
28 | }
29 |
30 | @Override
31 | public void onActivityResumed(Activity activity) {
32 | Log.d(TAG, "onActivityResumed, " + activity);
33 | }
34 |
35 | @Override
36 | public void onActivityPaused(Activity activity) {
37 | Log.d(TAG, "onActivityPaused, " + activity);
38 | }
39 |
40 | @Override
41 | public void onActivityStopped(Activity activity) {
42 | Log.d(TAG, "onActivityStopped, " + activity);
43 | }
44 |
45 | @Override
46 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
47 | Log.d(TAG, "onActivitySaveInstanceState, " + activity);
48 | }
49 |
50 | @Override
51 | public void onActivityDestroyed(Activity activity) {
52 | Log.d(TAG, "onActivityDestroyed, " + activity);
53 | }
54 | });
55 | }
56 | }
57 |
58 |
59 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/multiprocess/ProcessActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.multiprocess;
2 |
3 | import com.sample.R;
4 |
5 | import android.app.Activity;
6 | import android.content.ComponentName;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.ServiceConnection;
10 | import android.os.Bundle;
11 | import android.os.IBinder;
12 | import android.util.Log;
13 | import android.view.View;
14 |
15 | public class ProcessActivity extends Activity {
16 |
17 | private static String TAG = "ProcessActivity";
18 |
19 | boolean mBound = false;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_process);
25 |
26 | findViewById(R.id.butStart).setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | binderToService();
30 | }
31 | });
32 | }
33 |
34 | @Override
35 | protected void onResume() {
36 | super.onResume();
37 | }
38 |
39 | private void binderToService() {
40 | Intent intent = new Intent(ProcessActivity.this.getApplicationContext(), ProcessService.class);
41 | //startService(intent);
42 | boolean ret = this.getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
43 | Log.d(TAG, "binderToService,ret:" + ret);
44 | }
45 |
46 | /**
47 | * Defines callbacks for service binding, passed to bindService()
48 | */
49 | private ServiceConnection mConnection = new ServiceConnection() {
50 |
51 | @Override
52 | public void onServiceConnected(ComponentName className,
53 | IBinder service) {
54 | // We've bound to LocalService, cast the IBinder and get LocalService instance
55 | //LocalBinder binder = (LocalBinder) service;
56 | //mService = binder.getService();
57 | Log.d(TAG, "onServiceConnected");
58 | mBound = true;
59 | }
60 |
61 | @Override
62 | public void onServiceDisconnected(ComponentName arg0) {
63 | Log.d(TAG, "onServiceDisconnected");
64 | mBound = false;
65 | }
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/multiprocess/ProcessService.java:
--------------------------------------------------------------------------------
1 | package com.sample.multiprocess;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.util.Log;
7 |
8 | public class ProcessService extends Service {
9 |
10 | private final String TAG = "ProcessService";
11 |
12 | @Override
13 | public IBinder onBind(Intent intent) {
14 | Log.d(TAG, "onBind");
15 | return null;
16 | }
17 |
18 | @Override
19 | public int onStartCommand(Intent intent, int flags, int startId) {
20 | return super.onStartCommand(intent, flags, startId);
21 | }
22 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/myTextView.java:
--------------------------------------------------------------------------------
1 | package com.sample;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Rect;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.widget.TextView;
10 |
11 |
12 | /**
13 | * Created by clarkehe on 1/15/16.
14 | * Todo:
15 | */
16 | public class myTextView extends TextView {
17 |
18 | private static final String TAG = "myTextView";
19 |
20 | public myTextView(Context context) {
21 | super(context);
22 | }
23 |
24 | public myTextView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | }
27 |
28 | public myTextView(Context context, AttributeSet attrs, int defStyle) {
29 | super(context, attrs, defStyle);
30 | }
31 |
32 | @Override
33 | protected void onDraw(Canvas canvas) {
34 | super.onDraw(canvas);
35 |
36 | Paint.FontMetrics fontMetrics = this.getPaint().getFontMetrics();
37 | Log.d(TAG, "ascent: " + fontMetrics.ascent);
38 | Log.d(TAG, "descent: " + fontMetrics.descent);
39 | Log.d(TAG, "top: " + fontMetrics.top);
40 | Log.d(TAG, "bottom: " + fontMetrics.bottom);
41 | Log.d(TAG, "leading: " + fontMetrics.leading);
42 |
43 |
44 | String str = this.getText().toString();
45 | //str = "一";
46 | Rect rect = new Rect();
47 | this.getPaint().getTextBounds(str, 0, str.length(), rect);
48 | Log.d(TAG, rect.toString());
49 | }
50 |
51 | @Override
52 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
53 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
54 |
55 | final int width = getMeasuredWidth();
56 | final int height = getMeasuredHeight();
57 |
58 | Log.d(TAG, "width: " + width);
59 | Log.d(TAG, "height: " + height);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/network/NetworkActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.network;
2 |
3 | import android.app.Activity;
4 | import android.os.AsyncTask;
5 | import android.os.Bundle;
6 |
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.TextView;
10 |
11 | import com.facebook.network.connectionclass.*;
12 | import com.sample.R;
13 |
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.net.URL;
17 | import java.net.URLConnection;
18 |
19 | public class NetworkActivity extends Activity {
20 |
21 | private static final String TAG = "ConnectionClass-Sample";
22 |
23 | private ConnectionClassManager mConnectionClassManager;
24 | private DeviceBandwidthSampler mDeviceBandwidthSampler;
25 | private ConnectionChangedListener mListener;
26 | private TextView mTextView;
27 | private View mRunningBar;
28 |
29 | private String mURL = "http://connectionclass.parseapp.com/m100_hubble_4060.jpg";
30 | private int mTries = 0;
31 | private ConnectionQuality mConnectionClass = ConnectionQuality.UNKNOWN;
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_network);
37 |
38 | mConnectionClassManager = ConnectionClassManager.getInstance();
39 | mDeviceBandwidthSampler = DeviceBandwidthSampler.getInstance();
40 |
41 | findViewById(R.id.test_btn).setOnClickListener(testButtonClicked);
42 | mTextView = (TextView) findViewById(R.id.connection_class);
43 | mTextView.setText(mConnectionClassManager.getCurrentBandwidthQuality().toString());
44 |
45 | mRunningBar = findViewById(R.id.runningBar);
46 | mRunningBar.setVisibility(View.GONE);
47 |
48 | mListener = new ConnectionChangedListener();
49 | }
50 |
51 | @Override
52 | protected void onPause() {
53 | super.onPause();
54 | mConnectionClassManager.remove(mListener);
55 | }
56 |
57 | @Override
58 | protected void onResume() {
59 | super.onResume();
60 | mConnectionClassManager.register(mListener);
61 | }
62 |
63 | /**
64 | * Listener to update the UI upon connectionclass change.
65 | */
66 | private class ConnectionChangedListener
67 | implements ConnectionClassManager.ConnectionClassStateChangeListener {
68 |
69 | @Override
70 | public void onBandwidthStateChange(ConnectionQuality bandwidthState) {
71 | mConnectionClass = bandwidthState;
72 | runOnUiThread(new Runnable() {
73 | @Override
74 | public void run() {
75 | mTextView.setText(mConnectionClass.toString());
76 | }
77 | });
78 | }
79 | }
80 |
81 | private final View.OnClickListener testButtonClicked = new View.OnClickListener() {
82 | @Override
83 | public void onClick(View v) {
84 | new DownloadImage().execute(mURL);
85 | }
86 | };
87 |
88 | /**
89 | * AsyncTask for handling downloading and making calls to the timer.
90 | */
91 | private class DownloadImage extends AsyncTask {
92 |
93 | @Override
94 | protected void onPreExecute() {
95 | mDeviceBandwidthSampler.startSampling();
96 | mRunningBar.setVisibility(View.VISIBLE);
97 | }
98 |
99 | @Override
100 | protected Void doInBackground(String... url) {
101 | String imageURL = url[0];
102 | try {
103 | // Open a stream to download the image from our URL.
104 | URLConnection connection = new URL(imageURL).openConnection();
105 | connection.setUseCaches(false);
106 | connection.connect();
107 | InputStream input = connection.getInputStream();
108 | try {
109 | byte[] buffer = new byte[1024];
110 |
111 | // Do some busy waiting while the stream is open.
112 | while (input.read(buffer) != -1) {
113 | }
114 | } finally {
115 | input.close();
116 | }
117 | } catch (IOException e) {
118 | Log.e(TAG, "Error while downloading image.");
119 | }
120 | return null;
121 | }
122 |
123 | @Override
124 | protected void onPostExecute(Void v) {
125 | mDeviceBandwidthSampler.stopSampling();
126 | // Retry for up to 10 times until we find a ConnectionClass.
127 | if (mConnectionClass == ConnectionQuality.UNKNOWN && mTries < 10) {
128 | mTries++;
129 | new DownloadImage().execute(mURL);
130 | }
131 | if (!mDeviceBandwidthSampler.isSampling()) {
132 | mRunningBar.setVisibility(View.GONE);
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/opengles/GLSurf.java:
--------------------------------------------------------------------------------
1 | package com.sample.opengles;
2 |
3 | import android.content.Context;
4 | import android.opengl.GLSurfaceView;
5 |
6 | public class GLSurf extends GLSurfaceView {
7 |
8 | private final GLRenderer mRenderer;
9 |
10 | public GLSurf(Context context) {
11 | super(context);
12 |
13 | // Create an OpenGL ES 2.0 context.
14 | setEGLContextClientVersion(2);
15 |
16 | // Set the Renderer for drawing on the GLSurfaceView
17 | mRenderer = new GLRenderer(context);
18 | setRenderer(mRenderer);
19 |
20 | // Render the view only when there is a change in the drawing data
21 | setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
22 | }
23 |
24 | @Override
25 | public void onPause() {
26 | super.onPause();
27 | mRenderer.onPause();
28 | }
29 |
30 | @Override
31 | public void onResume() {
32 | super.onResume();
33 | mRenderer.onResume();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/opengles/OpenGLActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.opengles;
2 |
3 | import android.opengl.GLSurfaceView;
4 | import android.os.Bundle;
5 | import android.app.Activity;
6 | import android.view.Window;
7 | import android.view.WindowManager;
8 | import android.widget.RelativeLayout;
9 |
10 | import com.sample.R;
11 |
12 | public class OpenGLActivity extends Activity {
13 |
14 | // Our OpenGL Surfaceview
15 | private GLSurfaceView glSurfaceView;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 |
20 | // Turn off the window's title bar
21 | requestWindowFeature(Window.FEATURE_NO_TITLE);
22 |
23 | // Super
24 | super.onCreate(savedInstanceState);
25 |
26 | // Fullscreen mode
27 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
28 |
29 | // We create our Surfaceview for our OpenGL here.
30 | glSurfaceView = new GLSurf(this);
31 |
32 | // Set our view.
33 | setContentView(R.layout.activity_opengl);
34 |
35 | // Retrieve our Relative layout from our main layout we just set to our view.
36 | RelativeLayout layout = (RelativeLayout) findViewById(R.id.gamelayout);
37 |
38 | // Attach our surfaceview to our relative layout from our main layout.
39 | RelativeLayout.LayoutParams glParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
40 | layout.addView(glSurfaceView, glParams);
41 | }
42 |
43 | @Override
44 | protected void onPause() {
45 | super.onPause();
46 | glSurfaceView.onPause();
47 | }
48 |
49 | @Override
50 | protected void onResume() {
51 | super.onResume();
52 | glSurfaceView.onResume();
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/opengles/riGraphicTools.java:
--------------------------------------------------------------------------------
1 | package com.sample.opengles;
2 |
3 | import android.opengl.GLES20;
4 |
5 | public class riGraphicTools {
6 |
7 | // Program variables
8 | public static int sp_SolidColor;
9 | public static int sp_Image;
10 |
11 |
12 | /* SHADER Solid
13 | *
14 | * This shader is for rendering a colored primitive.
15 | *
16 | */
17 | public static final String vs_SolidColor =
18 | "uniform mat4 uMVPMatrix;" +
19 | "attribute vec4 vPosition;" +
20 | "void main() {" +
21 | " gl_Position = uMVPMatrix * vPosition;" +
22 | "}";
23 |
24 | public static final String fs_SolidColor =
25 | "precision mediump float;" +
26 | "void main() {" +
27 | " gl_FragColor = vec4(0.5,0,0,1);" +
28 | "}";
29 |
30 | /* SHADER Image
31 | *
32 | * This shader is for rendering 2D images straight from a texture
33 | * No additional effects.
34 | *
35 | */
36 | public static final String vs_Image =
37 | "uniform mat4 uMVPMatrix;" +
38 | "attribute vec4 vPosition;" +
39 | "attribute vec2 a_texCoord;" +
40 | "varying vec2 v_texCoord;" +
41 | "void main() {" +
42 | " gl_Position = uMVPMatrix * vPosition;" +
43 | " v_texCoord = a_texCoord;" +
44 | "}";
45 |
46 | public static final String fs_Image =
47 | "precision mediump float;" +
48 | "varying vec2 v_texCoord;" +
49 | "uniform sampler2D s_texture;" +
50 | "void main() {" +
51 | " gl_FragColor = texture2D( s_texture, v_texCoord );" +
52 | "}";
53 |
54 |
55 | public static int loadShader(int type, String shaderCode) {
56 |
57 | // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
58 | // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
59 | int shader = GLES20.glCreateShader(type);
60 |
61 | // add the source code to the shader and compile it
62 | GLES20.glShaderSource(shader, shaderCode);
63 | GLES20.glCompileShader(shader);
64 |
65 | // return the shader
66 | return shader;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/performance/ReflectHelper.java:
--------------------------------------------------------------------------------
1 | package com.sample.performance;
2 |
3 | import android.util.Log;
4 |
5 | import java.lang.reflect.Field;
6 | import java.lang.reflect.Method;
7 |
8 | public class ReflectHelper {
9 |
10 | public static Object getField(Class> clazz, String fieldName, Object instance) {
11 | Field field;
12 | try {
13 | field = clazz.getDeclaredField(fieldName);
14 | field.setAccessible(true);
15 | return field.get(instance);
16 | } catch (Exception e) {
17 | e.printStackTrace();
18 | return null;
19 | }
20 | }
21 |
22 | public static Object getField(String className, String fieldName, Object instance) {
23 | try {
24 | Class> clazz = Class.forName(className);
25 | return getField(clazz, fieldName, instance);
26 | } catch (Exception e) {
27 | e.printStackTrace();
28 | return null;
29 | }
30 | }
31 |
32 | public static void setField(Class> clazz, String fieldName, Object value, Object instance) {
33 | Field field;
34 | try {
35 | field = clazz.getDeclaredField(fieldName);
36 | field.setAccessible(true);
37 | field.set(instance, value);
38 | } catch (Exception e) {
39 | e.printStackTrace();
40 | }
41 | }
42 |
43 | public static void setField(String className, String fieldName, Object value, Object instance) {
44 | try {
45 | Class> clazz = Class.forName(className);
46 | setField(clazz, fieldName, value, instance);
47 | } catch (Exception e) {
48 | e.printStackTrace();
49 |
50 | }
51 | }
52 |
53 | public static Object invokeMethod(Class> clazz, String methodName, Object instance, Class>[] paramTypes, Object[] params) {
54 | Method method;
55 | try {
56 | method = clazz.getDeclaredMethod(methodName, paramTypes);
57 | method.setAccessible(true);
58 | return method.invoke(instance, params);
59 | } catch (Exception e) {
60 | e.printStackTrace();
61 | return null;
62 | }
63 | }
64 |
65 | public static Object invokeMethod(String className, String methodName, Object instance, Class>[] paramTypes, Object[] params) {
66 | try {
67 | Class> clazz = Class.forName(className);
68 | return invokeMethod(clazz, methodName, instance, paramTypes, params);
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | return null;
72 | }
73 | }
74 |
75 | public static long getInstanceCount(Class> find) {
76 | long start = System.currentTimeMillis();
77 | long result = 0;
78 | try {
79 | Class> clazz = Class.forName("dalvik.system.VMDebug");
80 | Method method = clazz.getMethod("countInstancesOfClass", Class.class, boolean.class);
81 | result = (Long) method.invoke(null, find, false);
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | result = 0;
85 | }
86 | Log.e("fuck", "use time===" + (System.currentTimeMillis() - start));
87 | return result;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/performance/TooDeepViewStackException.java:
--------------------------------------------------------------------------------
1 | package com.sample.performance;
2 |
3 | public class TooDeepViewStackException extends RuntimeException
4 | {
5 | private static final long serialVersionUID = 9145361450217030369L;
6 |
7 | public TooDeepViewStackException(String detailMessage)
8 | {
9 | super(detailMessage);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/performance/ViewHericacy.java:
--------------------------------------------------------------------------------
1 | package com.sample.performance;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Application;
5 | import android.os.Build;
6 |
7 | /**
8 | * Created by clarkehe on 1/18/16.
9 | * Todo:
10 | */
11 | public class ViewHericacy {
12 |
13 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
14 | public static void trackViewTreeDepth (Application app)
15 | {
16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
17 | {
18 | app.registerActivityLifecycleCallbacks(new ViewTreeTracer());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/activity/StubActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin.activity;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * 原始的Activity; 这个Activity会在Manifest中注册;
7 | * 当启动这个Activity的时候, 我们会把它拦截;然后跳转到TargetActivity
8 | *
9 | * 用到插件里面的话,那么就是在宿主程序里面注册了一堆空的Activity
10 | *
11 | * 如果希望启动插件的Activity; 由于插件Activity没有在主程序的Manifest中注册
12 | * 因此直接启动肯定会问题(插件的Activity有可能在它自己的Manifest.xml 中注册
13 | * 但是由于插件并不是一个真正安装的程序, Android系统并不知道这件事
14 | *
15 | * 我们可以通过分析Activity的启动机制, 可以在"合适的时候" 进行偷梁换柱,
16 | * 虽然我们要启动TargetActivity; 但是我们在真正启动之前,暂时替换为RawActivity
17 | * 这样,就能绕过AMS的验证,最后真正启动的时候,我们再替换回来,保证启动的是我们自己
18 | *
19 | * 这样我们就成为了一个真正的Activity, 生命周期由系统管理!
20 | * Created by weishu on 16/1/7.
21 | */
22 | public class StubActivity extends Activity {
23 | // dummy, just stub
24 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/activity/TargetActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin.activity;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.widget.TextView;
7 |
8 | /**
9 | * 要注意的是,这个Activity并没有再Manifest中注册!!!
10 | *
11 | * 且看我们如何瞒天过海, 成功启动它.
12 | *
13 | * Created by weishu on 16/1/7.
14 | */
15 | public class TargetActivity extends Activity {
16 |
17 | private static final String TAG = "TargetActivity";
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | Log.d(TAG, "onCreate() called with " + "savedInstanceState = [" + savedInstanceState + "]");
23 | TextView tv = new TextView(this);
24 | tv.setText("TargetActivity 启动成功!!!");
25 | setContentView(tv);
26 |
27 | }
28 |
29 | @Override
30 | protected void onPause() {
31 | super.onPause();
32 | Log.d(TAG, "onPause() called with " + "");
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | Log.d(TAG, "onResume() called with " + "");
39 | }
40 |
41 | @Override
42 | protected void onStop() {
43 | super.onStop();
44 | Log.d(TAG, "onStop() called with " + "");
45 | }
46 |
47 | @Override
48 | protected void onDestroy() {
49 | super.onDestroy();
50 | Log.d(TAG, "onDestroy() called with " + "");
51 | }
52 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/activity/hook/AMSHookHelper.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin.activity.hook;
2 |
3 | import java.lang.reflect.Field;
4 | import java.lang.reflect.InvocationTargetException;
5 | import java.lang.reflect.Proxy;
6 |
7 | import android.os.Handler;
8 |
9 | /**
10 | * @author weishu
11 | * @date 16/3/21
12 | */
13 | public class AMSHookHelper {
14 |
15 | public static final String EXTRA_TARGET_INTENT = "extra_target_intent";
16 |
17 | /**
18 | * Hook AMS
19 | *
20 | * 主要完成的操作是 "把真正要启动的Activity临时替换为在AndroidManifest.xml中声明的替身Activity"
21 | *
22 | * 进而骗过AMS
23 | *
24 | * @throws ClassNotFoundException
25 | * @throws NoSuchMethodException
26 | * @throws InvocationTargetException
27 | * @throws IllegalAccessException
28 | * @throws NoSuchFieldException
29 | */
30 | public static void hookActivityManagerNative() throws ClassNotFoundException,
31 | NoSuchMethodException, InvocationTargetException,
32 | IllegalAccessException, NoSuchFieldException {
33 |
34 | // 17package android.util;
35 | // 18
36 | // 19/**
37 | // 20 * Singleton helper class for lazily initialization.
38 | // 21 *
39 | // 22 * Modeled after frameworks/base/include/utils/Singleton.h
40 | // 23 *
41 | // 24 * @hide
42 | // 25 */
43 | // 26public abstract class Singleton {
44 | // 27 private T mInstance;
45 | // 28
46 | // 29 protected abstract T create();
47 | // 30
48 | // 31 public final T get() {
49 | // 32 synchronized (this) {
50 | // 33 if (mInstance == null) {
51 | // 34 mInstance = create();
52 | // 35 }
53 | // 36 return mInstance;
54 | // 37 }
55 | // 38 }
56 | // 39}
57 | // 40
58 |
59 | Class> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
60 |
61 | Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
62 | gDefaultField.setAccessible(true);
63 |
64 | Object gDefault = gDefaultField.get(null);
65 |
66 | // gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
67 | Class> singleton = Class.forName("android.util.Singleton");
68 | Field mInstanceField = singleton.getDeclaredField("mInstance");
69 | mInstanceField.setAccessible(true);
70 |
71 | // ActivityManagerNative 的gDefault对象里面原始的 IActivityManager对象
72 | Object rawIActivityManager = mInstanceField.get(gDefault);
73 |
74 | // 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
75 | Class> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
76 | Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
77 | new Class>[]{iActivityManagerInterface}, new IActivityManagerHandler(rawIActivityManager));
78 | mInstanceField.set(gDefault, proxy);
79 |
80 | }
81 |
82 | /**
83 | * 由于之前我们用替身欺骗了AMS; 现在我们要换回我们真正需要启动的Activity
84 | *
85 | * 不然就真的启动替身了, 狸猫换太子...
86 | *
87 | * 到最终要启动Activity的时候,会交给ActivityThread 的一个内部类叫做 H 来完成
88 | * H 会完成这个消息转发; 最终调用它的callback
89 | */
90 | public static void hookActivityThreadHandler() throws Exception {
91 |
92 | // 先获取到当前的ActivityThread对象
93 | Class> activityThreadClass = Class.forName("android.app.ActivityThread");
94 | Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
95 | currentActivityThreadField.setAccessible(true);
96 | Object currentActivityThread = currentActivityThreadField.get(null);
97 |
98 | // 由于ActivityThread一个进程只有一个,我们获取这个对象的mH
99 | Field mHField = activityThreadClass.getDeclaredField("mH");
100 | mHField.setAccessible(true);
101 | Handler mH = (Handler) mHField.get(currentActivityThread);
102 |
103 | // 设置它的回调, 根据源码:
104 | // 我们自己给他设置一个回调,就会替代之前的回调;
105 |
106 | // public void dispatchMessage(Message msg) {
107 | // if (msg.callback != null) {
108 | // handleCallback(msg);
109 | // } else {
110 | // if (mCallback != null) {
111 | // if (mCallback.handleMessage(msg)) {
112 | // return;
113 | // }
114 | // }
115 | // handleMessage(msg);
116 | // }
117 | // }
118 |
119 | Field mCallBackField = Handler.class.getDeclaredField("mCallback");
120 | mCallBackField.setAccessible(true);
121 |
122 | mCallBackField.set(mH, new ActivityThreadHandlerCallback(mH));
123 |
124 | }
125 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/activity/hook/ActivityThreadHandlerCallback.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin.activity.hook;
2 |
3 | import java.lang.reflect.Field;
4 |
5 | import android.content.Intent;
6 | import android.os.Handler;
7 | import android.os.Message;
8 |
9 | /**
10 | * @author weishu
11 | * @date 16/1/7
12 | */
13 | /* package */ class ActivityThreadHandlerCallback implements Handler.Callback {
14 |
15 | Handler mBase;
16 |
17 | public ActivityThreadHandlerCallback(Handler base) {
18 | mBase = base;
19 | }
20 |
21 | @Override
22 | public boolean handleMessage(Message msg) {
23 |
24 | switch (msg.what) {
25 | // ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100
26 | // 本来使用反射的方式获取最好, 这里为了简便直接使用硬编码
27 | case 100:
28 | handleLaunchActivity(msg);
29 | break;
30 | }
31 |
32 | mBase.handleMessage(msg);
33 | return true;
34 | }
35 |
36 | private void handleLaunchActivity(Message msg) {
37 | // 这里简单起见,直接取出TargetActivity;
38 |
39 | Object obj = msg.obj;
40 | // 根据源码:
41 | // 这个对象是 ActivityClientRecord 类型
42 | // 我们修改它的intent字段为我们原来保存的即可.
43 | // switch (msg.what) {
44 | // case LAUNCH_ACTIVITY: {
45 | // Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
46 | // final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
47 |
48 | // r.packageInfo = getPackageInfoNoCheck(
49 | // r.activityInfo.applicationInfo, r.compatInfo);
50 | // handleLaunchActivity(r, null);
51 |
52 |
53 | try {
54 | // 把替身恢复成真身
55 | Field intent = obj.getClass().getDeclaredField("intent");
56 | intent.setAccessible(true);
57 | Intent raw = (Intent) intent.get(obj);
58 |
59 | Intent target = raw.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT);
60 | raw.setComponent(target.getComponent());
61 |
62 | } catch (NoSuchFieldException e) {
63 | e.printStackTrace();
64 | } catch (IllegalAccessException e) {
65 | e.printStackTrace();
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/activity/hook/IActivityManagerHandler.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin.activity.hook;
2 |
3 | import java.lang.reflect.InvocationHandler;
4 | import java.lang.reflect.Method;
5 |
6 | import android.content.ComponentName;
7 | import android.content.Intent;
8 | import android.util.Log;
9 |
10 | import com.sample.plugin.activity.StubActivity;
11 |
12 |
13 | /**
14 | * @author weishu
15 | * @dete 16/1/7.
16 | */
17 | /* package */ class IActivityManagerHandler implements InvocationHandler {
18 |
19 | private static final String TAG = "IActivityManagerHandler";
20 |
21 | Object mBase;
22 |
23 | public IActivityManagerHandler(Object base) {
24 | mBase = base;
25 | }
26 |
27 | @Override
28 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
29 |
30 | if ("startActivity".equals(method.getName())) {
31 | // 只拦截这个方法
32 | // 替换参数, 任你所为;甚至替换原始Activity启动别的Activity偷梁换柱
33 | // API 23:
34 | // public final Activity startActivityNow(Activity parent, String id,
35 | // Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
36 | // Activity.NonConfigurationInstances lastNonConfigurationInstances) {
37 |
38 | // 找到参数里面的第一个Intent 对象
39 |
40 | Intent raw;
41 | int index = 0;
42 |
43 | for (int i = 0; i < args.length; i++) {
44 | if (args[i] instanceof Intent) {
45 | index = i;
46 | break;
47 | }
48 | }
49 | raw = (Intent) args[index];
50 |
51 | Intent newIntent = new Intent();
52 |
53 | // 替身Activity的包名, 也就是我们自己的包名
54 | String stubPackage = "com.sample";
55 |
56 | // 这里我们把启动的Activity临时替换为 StubActivity
57 | ComponentName componentName = new ComponentName(stubPackage, StubActivity.class.getName());
58 | newIntent.setComponent(componentName);
59 |
60 | // 把我们原始要启动的TargetActivity先存起来
61 | newIntent.putExtra(AMSHookHelper.EXTRA_TARGET_INTENT, raw);
62 |
63 | // 替换掉Intent, 达到欺骗AMS的目的
64 | args[index] = newIntent;
65 |
66 | Log.d(TAG, "hook success");
67 | return method.invoke(mBase, args);
68 | }
69 |
70 | return method.invoke(mBase, args);
71 | }
72 | }
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/pluginInstall.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin;
2 |
3 | // 插件是独立APK, 需要自己安装
4 |
5 | public class pluginInstall {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/plugin/pluginLoad.java:
--------------------------------------------------------------------------------
1 | package com.sample.plugin;
2 |
3 | /**
4 | * Created by clarkehe on 29/7/16.
5 | */
6 | public class pluginLoad {
7 | }
8 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/record/RecordActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.record;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 |
7 | import com.android.grafika.gles.EglCore;
8 | import com.android.grafika.gles.FullFrameRect;
9 | import com.android.grafika.gles.OffscreenSurface;
10 | import com.android.grafika.gles.Texture2dProgram;
11 | import com.sample.R;
12 | import com.tencent.qqgamemi.srp.media.newapi.ScreenRecorderManager;
13 |
14 | public class RecordActivity extends Activity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_record);
20 |
21 | findViewById(R.id.butStart).setOnClickListener(new View.OnClickListener() {
22 | @Override
23 | public void onClick(View v) {
24 |
25 | test();
26 |
27 | // boolean ret = ScreenCapture.requestPermission(RecordActivity.this, new Runnable() {
28 | // @Override
29 | // public void run() {
30 | // ScreenRecorderManager.getInstance().startRecord(RecordActivity.this,
31 | // ScreenCapture.gerResultCode(), ScreenCapture.getData());
32 | // }
33 | // });
34 | //
35 | // if (ret){
36 | // ScreenRecorderManager.getInstance().startRecord(RecordActivity.this,
37 | // ScreenCapture.gerResultCode(), ScreenCapture.getData());
38 | // }
39 | }
40 | });
41 |
42 | findViewById(R.id.butStop).setOnClickListener(new View.OnClickListener() {
43 | @Override
44 | public void onClick(View v) {
45 |
46 | ScreenRecorderManager.getInstance().stopRecord(RecordActivity.this);
47 | }
48 | });
49 | }
50 |
51 | private void test() {
52 | final int width = 100;
53 | final int height = 100;
54 |
55 | EglCore mEglCore = new EglCore(null, EglCore.FLAG_RECORDABLE);
56 |
57 | //mOffscreenSurface在此处作用???
58 | OffscreenSurface mOffscreenSurface = new OffscreenSurface(mEglCore, width, height);
59 | mOffscreenSurface.makeCurrent();
60 |
61 | FullFrameRect mFullFrameBlit = new FullFrameRect(new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT));
62 | int mTextureId = mFullFrameBlit.createTextureObject();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/record/RecordUtil.java:
--------------------------------------------------------------------------------
1 | package com.sample.record;
2 |
3 | import android.os.Environment;
4 |
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 |
8 | /**
9 | * Created by clarkehe on 5/4/16.
10 | * Todo:
11 | */
12 | public class RecordUtil {
13 |
14 | public static final String getVideoPath() {
15 | return getVideoRootPath() + "ScreenRecord";
16 | }
17 |
18 | public static final String getVideoRootPath() {
19 | return Environment.getExternalStorageDirectory().getAbsolutePath()
20 | + "/Tencent/shouyoubao/";
21 | }
22 |
23 | public static String getRecordVideoPath() {
24 | SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
25 | String fileName = sDateFormat.format(new Date(System.currentTimeMillis())) + "-"
26 | + "test";
27 |
28 | return getVideoPath() + "/" + fileName + ".mp4";
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/record/ScreenCapture.java:
--------------------------------------------------------------------------------
1 | package com.sample.record;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.media.projection.MediaProjectionManager;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 |
11 |
12 | /**
13 | * Created by clarkehe on 3/24/16.
14 | * 5.0及以上申请录屏的权限
15 | */
16 | public class ScreenCapture {
17 |
18 | private final static String TAG = "ScreenCapture";
19 | private final static int REQUEST_CODE_SCREEN_CAPTURE = 1;
20 |
21 | private static boolean sGetPermissionSuccess = false;
22 | private static Runnable sRunnable;
23 |
24 | private static int sResultCode = 0;
25 | private static Intent sData = null;
26 |
27 | public static class TemActivity extends Activity {
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | requestScreenCapture(this);
32 | }
33 |
34 | @Override
35 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
36 | Log.i(TAG, "onActivityResult, requestCode:" + requestCode + ", resultCode:" + requestCode);
37 | super.onActivityResult(requestCode, resultCode, data);
38 | if (requestCode == REQUEST_CODE_SCREEN_CAPTURE) {
39 | if (resultCode == Activity.RESULT_OK) {
40 | sGetPermissionSuccess = true;
41 |
42 | sResultCode = resultCode;
43 | sData = data;
44 |
45 | new android.os.Handler().post(sRunnable);
46 |
47 | // SDKApiHelper.getInstance().runOnMainThread(sRunnable);
48 | // sRunnable = null;
49 |
50 | // QmiSdkApi.setScreenCaptureIntent(resultCode, data);
51 | }
52 | }
53 | finish();
54 | }
55 | }
56 |
57 | public static boolean requestPermission(Context context, Runnable runnable) {
58 | if (sGetPermissionSuccess) return true;
59 | sRunnable = runnable;
60 |
61 | final Intent intent = new Intent(context, TemActivity.class);
62 | if (!(context instanceof Activity)) {
63 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
64 | }
65 | context.startActivity(intent);
66 | return false;
67 | }
68 |
69 | public static int gerResultCode() {
70 | return sResultCode;
71 | }
72 |
73 | public static Intent getData() {
74 | return sData;
75 | }
76 |
77 | @TargetApi(21)
78 | static void requestScreenCapture(final Activity context) {
79 | final MediaProjectionManager manager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
80 | final Intent permissionIntent = manager.createScreenCaptureIntent();
81 | context.startActivityForResult(permissionIntent, REQUEST_CODE_SCREEN_CAPTURE);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/res_confuse/GetRes.java:
--------------------------------------------------------------------------------
1 | package com.sample.res_confuse;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 |
6 | import com.sample.R;
7 |
8 | import java.lang.reflect.Field;
9 |
10 | /**
11 | * 资源会混淆,有些资源引用或访问方式在混淆后会失效,需要注意。
12 | */
13 | public class GetRes {
14 |
15 | //在代码或资源中直接引用资源ID, 应该是不会有影响的。
16 | //要注意下面的两种方式:
17 |
18 | //1 不是修改源码混淆
19 | //2 R文件还是原ID, 没有混淆ID
20 | private int getStringResourceId(String fileName) {
21 | Field field = null;
22 | try {
23 | field = R.string.class.getField(fileName);
24 | } catch (NoSuchFieldException e) {
25 | return 0;
26 | }
27 | try {
28 | return field.getInt(null);
29 | } catch (IllegalAccessException e) {
30 | }
31 |
32 | return 0;
33 | }
34 |
35 | //读res文件夹及resources.arsc文件??
36 | private int getResId(Context context, String name) {
37 | Resources resources = context.getResources();
38 | return resources.getIdentifier(name, "string", context.getPackageName());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/sleep/SampleBootReceiver.java:
--------------------------------------------------------------------------------
1 | package com.sample.sleep;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | /**
8 | * This BroadcastReceiver automatically (re)starts the alarm when the device is
9 | * rebooted. This receiver is set to be disabled (android:enabled="false") in the
10 | * application's manifest file. When the user sets the alarm, the receiver is enabled.
11 | * When the user cancels the alarm, the receiver is disabled, so that rebooting the
12 | * device will not trigger this receiver.
13 | */
14 | // BEGIN_INCLUDE(autostart)
15 | public class SampleBootReceiver extends BroadcastReceiver {
16 | SampleAlarmReceiver alarm = new SampleAlarmReceiver();
17 |
18 | @Override
19 | public void onReceive(Context context, Intent intent) {
20 | if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
21 | alarm.setAlarm(context);
22 | }
23 | }
24 | }
25 | //END_INCLUDE(autostart)
26 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/sleep/SampleSchedulingService.java:
--------------------------------------------------------------------------------
1 | package com.sample.sleep;
2 |
3 | import android.app.IntentService;
4 | import android.app.NotificationManager;
5 | import android.app.PendingIntent;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.support.v4.app.NotificationCompat;
9 | import android.util.Log;
10 |
11 | import com.sample.R;
12 |
13 | import java.io.BufferedReader;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.io.InputStreamReader;
17 | import java.net.HttpURLConnection;
18 | import java.net.URL;
19 |
20 | /**
21 | * This {@code IntentService} does the app's actual work.
22 | * {@code SampleAlarmReceiver} (a {@code WakefulBroadcastReceiver}) holds a
23 | * partial wake lock for this service while the service does its work. When the
24 | * service is finished, it calls {@code completeWakefulIntent()} to release the
25 | * wake lock.
26 | */
27 | public class SampleSchedulingService extends IntentService {
28 | public SampleSchedulingService() {
29 | super("SchedulingService");
30 | }
31 |
32 | public static final String TAG = "Scheduling Demo";
33 | // An ID used to post the notification.
34 | public static final int NOTIFICATION_ID = 1;
35 | // The string the app searches for in the Google home page content. If the app finds
36 | // the string, it indicates the presence of a doodle.
37 | public static final String SEARCH_STRING = "doodle";
38 | // The Google home page URL from which the app fetches content.
39 | // You can find a list of other Google domains with possible doodles here:
40 | // http://en.wikipedia.org/wiki/List_of_Google_domains
41 | public static final String URL = "http://www.google.com";
42 | private NotificationManager mNotificationManager;
43 | NotificationCompat.Builder builder;
44 |
45 | @Override
46 | protected void onHandleIntent(Intent intent) {
47 | // BEGIN_INCLUDE(service_onhandle)
48 | // The URL from which to fetch content.
49 | String urlString = URL;
50 |
51 | String result = "";
52 |
53 | // Try to connect to the Google homepage and download content.
54 | try {
55 | result = loadFromNetwork(urlString);
56 | } catch (IOException e) {
57 | Log.i(TAG, "getString(R.string.connection_error)");
58 | }
59 |
60 | // If the app finds the string "doodle" in the Google home page content, it
61 | // indicates the presence of a doodle. Post a "Doodle Alert" notification.
62 | if (result.indexOf(SEARCH_STRING) != -1) {
63 | sendNotification("getString(R.string.doodle_found)");
64 | Log.i(TAG, "Found doodle!!");
65 | } else {
66 | sendNotification("getString(R.string.no_doodle)");
67 | Log.i(TAG, "No doodle found. :-(");
68 | }
69 | // Release the wake lock provided by the BroadcastReceiver.
70 | //SampleAlarmReceiver.completeWakefulIntent(intent);
71 | // END_INCLUDE(service_onhandle)
72 | }
73 |
74 | // Post a notification indicating whether a doodle was found.
75 | private void sendNotification(String msg) {
76 | mNotificationManager = (NotificationManager)
77 | this.getSystemService(Context.NOTIFICATION_SERVICE);
78 |
79 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
80 | new Intent(this, TestSleepActivity.class), 0);
81 |
82 | NotificationCompat.Builder mBuilder =
83 | new NotificationCompat.Builder(this)
84 | .setSmallIcon(R.drawable.ic_launcher)
85 | .setContentTitle("getString(R.string.doodle_alert)")
86 | .setStyle(new NotificationCompat.BigTextStyle()
87 | .bigText(msg))
88 | .setContentText(msg);
89 |
90 | mBuilder.setContentIntent(contentIntent);
91 | mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
92 | }
93 |
94 | //
95 | // The methods below this line fetch content from the specified URL and return the
96 | // content as a string.
97 | //
98 |
99 | /**
100 | * Given a URL string, initiate a fetch operation.
101 | */
102 | private String loadFromNetwork(String urlString) throws IOException {
103 | InputStream stream = null;
104 | String str = "";
105 |
106 | try {
107 | stream = downloadUrl(urlString);
108 | str = readIt(stream);
109 | } finally {
110 | if (stream != null) {
111 | stream.close();
112 | }
113 | }
114 | return str;
115 | }
116 |
117 | /**
118 | * Given a string representation of a URL, sets up a connection and gets
119 | * an input stream.
120 | *
121 | * @param urlString A string representation of a URL.
122 | * @return An InputStream retrieved from a successful HttpURLConnection.
123 | * @throws IOException
124 | */
125 | private InputStream downloadUrl(String urlString) throws IOException {
126 |
127 | URL url = new URL(urlString);
128 | HttpURLConnection conn = (HttpURLConnection) url.openConnection();
129 | conn.setReadTimeout(10000 /* milliseconds */);
130 | conn.setConnectTimeout(15000 /* milliseconds */);
131 | conn.setRequestMethod("GET");
132 | conn.setDoInput(true);
133 | // Start the query
134 | conn.connect();
135 | InputStream stream = conn.getInputStream();
136 | return stream;
137 | }
138 |
139 | /**
140 | * Reads an InputStream and converts it to a String.
141 | *
142 | * @param stream InputStream containing HTML from www.google.com.
143 | * @return String version of InputStream.
144 | * @throws IOException
145 | */
146 | private String readIt(InputStream stream) throws IOException {
147 |
148 | StringBuilder builder = new StringBuilder();
149 | BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
150 | for (String line = reader.readLine(); line != null; line = reader.readLine())
151 | builder.append(line);
152 | reader.close();
153 | return builder.toString();
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/sleep/TestSleepActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.sleep;
2 |
3 | import android.app.Activity;
4 | import android.app.AlarmManager;
5 | import android.app.PendingIntent;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.net.Uri;
10 | import android.os.Bundle;
11 | import android.os.Environment;
12 | import android.os.Handler;
13 | import android.os.HandlerThread;
14 | import android.os.Looper;
15 | import android.os.Message;
16 | import android.os.SystemClock;
17 | import android.util.Log;
18 | import android.widget.MediaController;
19 | import android.widget.VideoView;
20 |
21 | import com.sample.R;
22 |
23 | import java.util.Calendar;
24 |
25 | public class TestSleepActivity extends Activity {
26 |
27 | private static String TAG = "TestSleepActivity";
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_test_sleep);
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 |
39 | //postDelayedMsg();
40 |
41 | setAlarm(this);
42 |
43 | // createThread();
44 |
45 | // createThread1();
46 |
47 | //playVideo();
48 | }
49 |
50 | private void playVideo() {
51 | Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath() + "/test.mp4");
52 | Log.d(TAG, uri.toString());
53 | VideoView videoView = (VideoView) this.findViewById(R.id.videoView);
54 | videoView.setMediaController(new MediaController(this));
55 | videoView.setVideoURI(uri);
56 | videoView.start();
57 | videoView.requestFocus();
58 | }
59 |
60 | private void createThread1() {
61 | new Thread(new Runnable() {
62 | @Override
63 | public void run() {
64 | while (true) {
65 | try {
66 | Thread.sleep(10 * 1000);
67 | } catch (Exception e) {
68 |
69 | }
70 | Log.d(TAG, "Delayed Msg.");
71 | }
72 | }
73 | }).start();
74 | }
75 |
76 | private void createThread() {
77 | HandlerThread thread = new HandlerThread("test");
78 | thread.start();
79 |
80 | Handler handler = new Handler(thread.getLooper()) {
81 | @Override
82 | public void handleMessage(Message msg) {
83 | super.handleMessage(msg);
84 | }
85 | };
86 |
87 | postDelayedMsg(handler);
88 | }
89 |
90 | private void postDelayedMsg(final Handler handler) {
91 | handler.postDelayed(new Runnable() {
92 | @Override
93 | public void run() {
94 | Log.d(TAG, "Delayed Msg.");
95 | postDelayedMsg(handler);
96 | }
97 | }, 10 * 1000);
98 | }
99 |
100 | private void postDelayedMsg() {
101 | Handler mHandler = new Handler(Looper.getMainLooper());
102 |
103 | Runnable mRunnable = new Runnable() {
104 | @Override
105 | public void run() {
106 | Log.d(TAG, "Delayed Msg.");
107 | }
108 | };
109 |
110 | long delay = 5 * 60 * 1000;
111 | mHandler.postDelayed(mRunnable, delay);
112 | }
113 |
114 | static void setAlarm(Context context) {
115 | AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
116 |
117 | // Intent intent = new Intent(context, SimpleBroadCastReceiver.class);
118 | Intent intent = new Intent("com.sample.alarm");
119 | PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
120 |
121 | long delay = 10 * 1000;
122 | alarmMgr.setExact(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + delay, alarmIntent);
123 | }
124 |
125 | public static class SimpleBroadCastReceiver extends BroadcastReceiver {
126 | @Override
127 | public void onReceive(Context context, Intent intent) {
128 | Log.d(TAG, "SimpleBroadCastReceiver#onReceive");
129 | //setAlarm(SimpleBroadCastReceiver.this);
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/statsUsage/StatsUsageActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.statsUsage;
2 |
3 | import android.app.Activity;
4 | import android.app.ActivityManager;
5 | import android.app.usage.UsageEvents;
6 | import android.app.usage.UsageStatsManager;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.provider.Settings;
12 | import android.util.Log;
13 | import android.view.View;
14 |
15 | import com.sample.R;
16 |
17 | import java.util.List;
18 |
19 | public class StatsUsageActivity extends Activity {
20 |
21 | private final String TAG = this.getClass().getSimpleName();
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_stats_usage);
27 |
28 | findViewById(R.id.getButton).setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | start();
32 | }
33 | });
34 |
35 | findViewById(R.id.getTopApp).setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | getTop();
39 | }
40 | });
41 | }
42 |
43 | private void start() {
44 | Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
45 | this.startActivity(intent);
46 | }
47 |
48 | private void getTop() {
49 | new android.os.Handler().postDelayed(new Runnable() {
50 | @Override
51 | public void run() {
52 |
53 | final String topApp = getLauncherTopApp(StatsUsageActivity.this);
54 | Log.e(TAG, "topApp:" + topApp);
55 |
56 | getTop();
57 | }
58 | }, 500);
59 | }
60 |
61 | static UsageStatsManager sUsageStatsManager = null;
62 |
63 | public static String getLauncherTopApp(Context context) {
64 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
65 | ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
66 | List appTasks = activityManager.getRunningTasks(1);
67 | if (null != appTasks && !appTasks.isEmpty()) {
68 | return appTasks.get(0).topActivity.getPackageName();
69 | }
70 | } else {
71 | long endTime = System.currentTimeMillis();
72 | long beginTime = endTime - 10000;
73 | if (sUsageStatsManager == null) {
74 | //sUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
75 | }
76 | String result = "";
77 | UsageEvents.Event event = new UsageEvents.Event();
78 | UsageEvents usageEvents = sUsageStatsManager.queryEvents(beginTime, endTime);
79 | while (usageEvents.hasNextEvent()) {
80 | usageEvents.getNextEvent(event);
81 | if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
82 | result = event.getPackageName();
83 | }
84 | }
85 | if (!android.text.TextUtils.isEmpty(result)) {
86 | return result;
87 | }
88 | }
89 | return "";
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/java/com/sample/web/WebViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.sample.web;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.Window;
8 | import android.webkit.JsPromptResult;
9 | import android.webkit.WebChromeClient;
10 | import android.webkit.WebResourceResponse;
11 | import android.webkit.WebView;
12 | import android.webkit.WebViewClient;
13 |
14 | import com.sample.BaseActivity;
15 | import com.sample.R;
16 |
17 | /**
18 | * Created by clarkehe on 1/18/16.
19 | * Todo:
20 | */
21 | public class WebViewActivity extends BaseActivity {
22 |
23 | private static final String TAG = "WebViewActivity";
24 |
25 | WebView mWebView;
26 |
27 | public WebViewActivity() {
28 | super();
29 | }
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 |
35 | // Let's display the progress in the activity title bar, like the
36 | // browser app does.
37 | getWindow().requestFeature(Window.FEATURE_PROGRESS);
38 |
39 | setContentView(R.layout.webview_activity);
40 |
41 | mWebView = (WebView)findViewById(R.id.webView);
42 | final WebView webView = mWebView;
43 |
44 | // 不设置,loadUrl会启动浏览器
45 | mWebView.setWebViewClient(new MyWebViewClient());
46 |
47 | //
48 | mWebView.setWebChromeClient(new MyWebChromeClient());
49 |
50 | // JS
51 | mWebView.getSettings().setJavaScriptEnabled(true);
52 |
53 | // mWebView.loadUrl("http://baidu.com");
54 | mWebView.loadUrl("file:///android_asset/www/index.html");
55 |
56 | //Load JS after Page Loaded
57 | //NATIVE CALL JS
58 | new android.os.Handler().postDelayed(new Runnable() {
59 | @Override
60 | public void run() {
61 | //. NATIVE CALL JS, 没有返回值。
62 | //webView.loadUrl("javascript:jsFun('Hello World!')");
63 | //webView.evaluateJavascript();
64 | }
65 | }, 1000);
66 |
67 | //1. JS CALL NATIVE. 不安全,有返回值。
68 | // webView.addJavascriptInterface(new JsObject(), "injectedObject");
69 | // webView.loadData(" ", "text/html", null);
70 | // webView.loadUrl("javascript:alert(injectedObject.toString())");
71 | }
72 |
73 | // class JsObject {
74 | // @JavascriptInterface
75 | // public String toString() { return "injectedObject"; }
76 | // }
77 |
78 | @Override
79 | public void onBackPressed() {
80 | if (mWebView.canGoBack()) {
81 | mWebView.goBack();
82 | } else {
83 | super.onBackPressed();
84 | }
85 | }
86 |
87 | private class MyWebViewClient extends WebViewClient
88 | {
89 | //JSBridge 2. JS CALL NATIVE,没有返回值
90 | //2. WX,使用的方式是在JS中存一个回CALLBACK, NATIVE来调用。
91 | @Override
92 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
93 | Log.d(TAG, "shouldOverrideUrlLoading, url:" + url);
94 | if (url.contains("jsbridge:")){
95 | return true;
96 | }
97 | return false;
98 | }
99 |
100 | //Load Native Cache Res
101 | @Override
102 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
103 | Log.d(TAG, "shouldInterceptRequest, url:" + url);
104 | return super.shouldInterceptRequest(view, url);
105 | }
106 |
107 | @Override
108 | public void onPageFinished(WebView view, String url) {
109 | super.onPageFinished(view, url);
110 | }
111 |
112 | @Override
113 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
114 | super.onPageStarted(view, url, favicon);
115 | }
116 | }
117 |
118 | class MyWebChromeClient extends WebChromeClient
119 | {
120 | // 3. JS CALL NATIVE, 有返回值。
121 | @Override
122 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
123 |
124 | Log.d(TAG, "onJsPrompt, url:" + url);
125 | Log.d(TAG, "onJsPrompt, message:" + message);
126 | Log.d(TAG, "onJsPrompt, defaultValue:" + defaultValue);
127 |
128 | if (message.contains("jsbridge:")){
129 | result.confirm("return");
130 | return true;
131 | }
132 |
133 | return super.onJsPrompt(view, url, message, defaultValue, result);
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/jniLibs/apatch-debug.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/jniLibs/apatch-debug.aar
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/drawable/startup_twinkle_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/drawable/ui_selector_iconfont_textview_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_animator.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_anr_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_attr_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_audio.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
23 |
24 |
33 |
34 |
43 |
44 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_glide.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
15 |
16 |
20 |
21 |
25 |
26 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_hot_fix.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_list_view_activty.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_mvc.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_mvp.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_network.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
21 |
22 |
27 |
28 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_opengl.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_process.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
21 |
22 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_record.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
19 |
20 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_stats_usage.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_test_crash.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/activity_test_sleep.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/content_list_view_activty.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/custom_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/layout_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/media_projection.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
16 |
17 |
23 |
24 |
29 |
36 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/rowlayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/layout/webview_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-xxhdpi/startup_twinkle_animation4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-xxhdpi/startup_twinkle_animation4.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #fafafa
7 |
8 | #ff00
9 |
10 |
11 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 | 10dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Sample
3 | App列表
4 |
5 | 䀀
6 |
7 | ǚ
8 |
9 | ʯ
10 | TestCrashActivity
11 |
12 | Test Connection
13 | Your connection class is:
14 | AudioActivity
15 |
16 |
17 |
--------------------------------------------------------------------------------
/code/Sample/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/code/Sample/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | maven { url project.MAVEN_URL }
6 | maven { url 'http://maven.oa.com/nexus/content/repositories/android' }
7 | maven { url 'http://maven.oa.com/nexus/content/repositories/thirdparty' }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:2.1.3'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | maven { url project.MAVEN_URL }
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/code/Sample/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | MAVEN_URL=http://maven.oa.com/nexus/content/groups/androidbuild/
21 |
--------------------------------------------------------------------------------
/code/Sample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/code/Sample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/code/Sample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Aug 31 16:15:07 CST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/code/Sample/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/code/Sample/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/code/Sample/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/doc/CBR、VBR、AVR.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/CBR、VBR、AVR.jpeg
--------------------------------------------------------------------------------
/doc/MemoryProfile_Big_Texture2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/MemoryProfile_Big_Texture2D.png
--------------------------------------------------------------------------------
/doc/MemoryProfile_Memory_Leak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/MemoryProfile_Memory_Leak.png
--------------------------------------------------------------------------------
/doc/android_event_dispatch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/android_event_dispatch.png
--------------------------------------------------------------------------------
/doc/android_framework.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/android_framework.gif
--------------------------------------------------------------------------------
/doc/android_meminfo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/android_meminfo.jpg
--------------------------------------------------------------------------------
/doc/android_tech_mind_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/android_tech_mind_map.png
--------------------------------------------------------------------------------
/doc/classloader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/classloader.png
--------------------------------------------------------------------------------
/doc/linux_sleep.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/linux_sleep.gif
--------------------------------------------------------------------------------
/doc/network_delay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/network_delay.png
--------------------------------------------------------------------------------
/doc/sleep_diagram.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/sleep_diagram.gif
--------------------------------------------------------------------------------
/doc/wake_diagram.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/wake_diagram.gif
--------------------------------------------------------------------------------
/doc/wake_type.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/wake_type.jpg
--------------------------------------------------------------------------------
/doc/wake_type_and_sleep.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clarkehe/Android/ebb4a4427d6e4e9d37e896841aa93f9c6ee2b1f3/doc/wake_type_and_sleep.jpg
--------------------------------------------------------------------------------