/** Resets the dirty region when the motion event occurs. */ private void resetDirtyRect(float eventX, float eventY) { // The lastTouchX and lastTouchY were set when the ACTION_DOWN // motion event occurred. dirtyRect.left = Math.min(lastTouchX, eventX); dirtyRect.right = Math.max(lastTouchX, eventX); dirtyRect.top = Math.min(lastTouchY, eventY); dirtyRect.bottom = Math.max(lastTouchY, eventY); }
// ============================================================================== public final int[] renderGlyph( char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds) { Path p = new Path(); paint.getTextPath(String.valueOf(glyph), 0, 1, 0.0f, 0.0f, p); RectF boundsF = new RectF(); p.computeBounds(boundsF, true); matrix.mapRect(boundsF); boundsF.roundOut(bounds); bounds.left--; bounds.right++; final int w = bounds.width(); final int h = Math.max(1, bounds.height()); Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); matrix.postTranslate(-bounds.left, -bounds.top); c.setMatrix(matrix); c.drawPath(p, paint); final int sizeNeeded = w * h; if (cachedRenderArray.length < sizeNeeded) cachedRenderArray = new int[sizeNeeded]; bm.getPixels(cachedRenderArray, 0, w, 0, 0, w, h); bm.recycle(); return cachedRenderArray; }
private int scrollBounds(int desiredScroll, int firstCell, int sizes[], int viewSize) { if (desiredScroll == 0) { // no op } else if (desiredScroll < 0) { desiredScroll = Math.max(desiredScroll, -sumArray(sizes, 1, firstCell)); } else { desiredScroll = Math.min( desiredScroll, Math.max( 0, sumArray(sizes, firstCell + 1, sizes.length - 1 - firstCell) + sizes[0] - viewSize)); } return desiredScroll; }
@Override public boolean getPadding(Rect padding) { padding.left = 0; padding.top = 0; padding.right = 0; padding.bottom = 0; final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { reapplyPadding(i, array[i]); padding.left = Math.max(padding.left, mPaddingL[i]); padding.top = Math.max(padding.top, mPaddingT[i]); padding.right = Math.max(padding.right, mPaddingR[i]); padding.bottom = Math.max(padding.bottom, mPaddingB[i]); } return true; }
// Grows the cropping rectange by (dx, dy) in image space. void moveBy(float dx, float dy) { Rect invalRect = new Rect(mDrawRect); mCropRect.offset(dx, dy); // Put the cropping rectangle inside image rectangle. mCropRect.offset( Math.max(0, mImageRect.left - mCropRect.left), Math.max(0, mImageRect.top - mCropRect.top)); mCropRect.offset( Math.min(0, mImageRect.right - mCropRect.right), Math.min(0, mImageRect.bottom - mCropRect.bottom)); mDrawRect = computeLayout(); invalRect.union(mDrawRect); invalRect.inset(-10, -10); mContext.invalidate(invalRect); }
// Audio public static void audioInit( int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); Log.v( "SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); // Let the user pick a larger buffer if they really want -- but ye // gods they probably shouldn't, the minimums are horrifyingly high // latency already desiredFrames = Math.max( desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); mAudioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); audioStartThread(); Log.v( "SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); }
/** * @param velocity * @return the page you should "land" on */ private int getNextPage(int velocity) { int nextPage; if (velocity > mMinimumVelocity) { nextPage = getCurrentPageFloor(); } else if (velocity < -mMinimumVelocity) { nextPage = getCurrentPageCeil(); } else { nextPage = getCurrentPageRound(); } return Math.min(Math.max(nextPage, 0), mPageCount - 1); }
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { int h = options.outHeight; int w = options.outWidth; int inSampleSize = 0; if (h > reqHeight || w > reqWidth) { float ratioW = (float) w / reqWidth; float ratioH = (float) h / reqHeight; inSampleSize = (int) Math.min(ratioH, ratioW); } inSampleSize = Math.max(1, inSampleSize); return inSampleSize; }
/** * 根据移动的距离来刷新原来的圆半径大小 * * @param distance */ private void refreshCurRadiusByMoveDistance(int distance) { if (distance > maxMoveLength) { isArrivedMaxMoved = true; curRadius = 0; } else { isArrivedMaxMoved = false; float calcRadius = (1 - 1f * distance / maxMoveLength) * originRadius; float maxRadius = ABTextUtil.dip2px(context, 2); curRadius = (int) Math.max(calcRadius, maxRadius); // Logger.d(TAG, "[refreshCurRadiusByMoveDistance]curRadius: " + curRadius + ", // calcRadius: " + calcRadius + ", maxRadius: " + maxRadius); } }
private void drawTown(Canvas canvas) { Matrix matrix = mMatrix; matrix.reset(); int y = Math.max(0, mTop - mTotalDragDistance); float dragPercent = Math.min(1f, Math.abs(mPercent)); float townScale; float townTopOffset; float townMoveOffset; float scalePercentDelta = dragPercent - SCALE_START_PERCENT; if (scalePercentDelta > 0) { /** * Change townScale between {@link #TOWN_INITIAL_SCALE} and {@link #TOWN_FINAL_SCALE} * depending on {@link #mPercent} Change townTopOffset between {@link #mTownInitialTopOffset} * and {@link #mTownFinalTopOffset} depending on {@link #mPercent} */ float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT); townScale = TOWN_INITIAL_SCALE + (TOWN_FINAL_SCALE - TOWN_INITIAL_SCALE) * scalePercent; townTopOffset = mTownInitialTopOffset - (mTownFinalTopOffset - mTownInitialTopOffset) * scalePercent; townMoveOffset = mTownMoveOffset * (1.0f - scalePercent); } else { float scalePercent = dragPercent / SCALE_START_PERCENT; townScale = TOWN_INITIAL_SCALE; townTopOffset = mTownInitialTopOffset; townMoveOffset = mTownMoveOffset * scalePercent; } float offsetX = -(mScreenWidth * townScale - mScreenWidth) / 2.0f; // float offsetY = (1.0f - dragPercent) * mTotalDragDistance // Offset canvas moving float offsetY = y + +townTopOffset - mTownHeight * (townScale - 1.0f) / 2 // Offset town scaling + townMoveOffset; // Give it a little move matrix.postScale(townScale, townScale); // 移动建筑的中心点 matrix.postTranslate(offsetX, offsetY); canvas.drawBitmap(mTown, matrix, null); }
private void drawSky(Canvas canvas) { Matrix matrix = mMatrix; matrix.reset(); int y = Math.max(0, mTop - mTotalDragDistance); // 0 ~ 1 float dragPercent = Math.min(1f, Math.abs(mPercent)); /** * Change skyScale between {@link #SKY_INITIAL_SCALE} and 1.0f depending on {@link #mPercent} */ // 根据拖动的比例改变天空的大小 float skyScale; float scalePercentDelta = dragPercent - SCALE_START_PERCENT; /** less than {@link SCALE_START_PERCENT} will be {@link SKY_INITIAL_SCALE} */ // 拖动比例小于0.3时使用默认的大小1.05 if (scalePercentDelta > 0) { /** will change from 0 ~ 1 * */ // skyScale = SKY_INITIAL_SCALE + (dragPercent - SCALE_START_PERCENT); float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT); skyScale = SKY_INITIAL_SCALE - (SKY_INITIAL_SCALE - 1.0f) * scalePercent; } else { skyScale = SKY_INITIAL_SCALE; } float offsetX = -(mScreenWidth * skyScale - mScreenWidth) / 2.0f; float offsetY = y + 50 + mSkyTopOffset // Offset canvas moving, goes lower when goes down - mSkyHeight * (skyScale - 1.0f) / 2 // Offset sky scaling, lower than 0, will go greater when goes down + mSkyMoveOffset * dragPercent; // Give it a little move top -> bottom // will go greater when goes // down matrix.postScale(skyScale, skyScale); matrix.postTranslate(offsetX, offsetY); canvas.drawBitmap(mSky, matrix, null); }
private int getMaxScrollY() { return Math.max(0, sumArray(heights) - height); }
private int getMaxScrollX() { return Math.max(0, sumArray(widths) - width); }
// Audio public static int audioInit( int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); Log.v( "SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); // Let the user pick a larger buffer if they really want -- but ye // gods they probably shouldn't, the minimums are horrifyingly high // latency already desiredFrames = Math.max( desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); if (mAudioTrack == null) { mAudioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); // Instantiating AudioTrack can "succeed" without an exception and the track may still be // invalid // Ref: // https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState() if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) { Log.e("SDL", "Failed during initialization of Audio Track"); mAudioTrack = null; return -1; } mAudioTrack.play(); } Log.v( "SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); return 0; }
public void build(MessageWireframe wireframe, int desiredWidth, StelsApplication application) { Logger.d(TAG, "Build layout start"); checkResources(application); senderPaint = initTextPaint(); senderPaint.setTypeface(FontController.loadTypeface(application, "regular")); senderPaint.setTextSize(bodyPaint.getTextSize()); senderPaint.setColor(0xff000000); forwardingPaint = initTextPaint(); forwardingPaint.setTypeface(FontController.loadTypeface(application, "light")); forwardingPaint.setTextSize(bodyPaint.getTextSize()); forwardingPaint.setColor(0xff000000); this.layoutDesiredWidth = desiredWidth; this.isOut = wireframe.message.isOut(); this.showState = isOut; this.isGroup = wireframe.message.getPeerType() == PeerType.PEER_CHAT && !isOut; if (isGroup) { User user = wireframe.senderUser; this.senderName = user.getDisplayName(); if (!wireframe.message.isForwarded()) { senderPaint.setColor( Placeholders.USER_PLACEHOLDERS_COLOR[ wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]); forwardingPaint.setColor( Placeholders.USER_PLACEHOLDERS_COLOR[ wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]); } } if (wireframe.message.isForwarded()) { isForwarded = true; this.forwarderName = wireframe.forwardUser.getDisplayName(); if (isOut) { forwardingPaint.setColor(0xff739f53); senderPaint.setColor(0xff739f53); } else { forwardingPaint.setColor(0xff4884cf); senderPaint.setColor(0xff4884cf); } } else { isForwarded = false; } if (isGroup) { User user = application.getEngine().getUser(wireframe.message.getSenderId()); this.senderName = user.getDisplayName(); } if (wireframe.message.isForwarded()) { isForwarded = true; this.forwarderName = wireframe.forwardUser.getDisplayName(); } else { isForwarded = false; } layoutDesiredWidth = desiredWidth; long start = SystemClock.uptimeMillis(); this.spannable = application .getEmojiProcessor() .processEmojiCompatMutable( wireframe.message.getMessage(), EmojiProcessor.CONFIGURATION_BUBBLES); // spannable = new SpannableString(wireframe.message.getMessage()); Logger.d(TAG, "Emoji processed in " + (SystemClock.uptimeMillis() - start) + " ms"); start = SystemClock.uptimeMillis(); Linkify.addLinks( this.spannable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES); fixLinks(spannable); Logger.d(TAG, "Added links in " + (SystemClock.uptimeMillis() - start) + " ms"); start = SystemClock.uptimeMillis(); layout = new StaticLayout( spannable, bodyPaint, desiredWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); Logger.d(TAG, "Built base layout in " + (SystemClock.uptimeMillis() - start) + " ms"); if (layout.getLineCount() < 20) { int layoutTextWidth = 0; for (int i = 0; i < layout.getLineCount(); i++) { layoutTextWidth = (int) Math.max(layout.getLineWidth(i), layoutTextWidth); } if (layoutTextWidth < layout.getWidth() - px(10)) { layout = new StaticLayout( spannable, bodyPaint, layoutTextWidth + px(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); } } layoutRealWidth = layout.getWidth(); timeWidth = (int) clockOutPaint.measureText(wireframe.date) + px((showState ? 23 : 0) + 6); if (layout.getLineCount() == 1) { boolean isLastRtl = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT; if (!isLastRtl && desiredWidth - layoutRealWidth > timeWidth) { layoutRealWidth += timeWidth; layoutHeight = layout.getHeight() + px(3); } else if (isLastRtl && desiredWidth - layout.getWidth() > timeWidth) { layoutRealWidth = layout.getWidth() + timeWidth; layoutHeight = layout.getHeight() + px(3); } else { if (isLastRtl) { layoutRealWidth = layout.getWidth(); } layoutHeight = layout.getHeight() + px(17); } } else { boolean isLastRtl = layout.getParagraphDirection(layout.getLineCount() - 1) == Layout.DIR_RIGHT_TO_LEFT; if (!isLastRtl && (desiredWidth - layout.getLineWidth(layout.getLineCount() - 1) > timeWidth)) { layoutRealWidth = (int) Math.max( layoutRealWidth, layout.getLineWidth(layout.getLineCount() - 1) + timeWidth); layoutHeight = layout.getHeight() + px(3); } else if (isLastRtl && (desiredWidth - layout.getWidth() > timeWidth)) { layoutRealWidth = (int) Math.max(layoutRealWidth, layout.getWidth() + timeWidth); layoutHeight = layout.getHeight() + px(3); } else { layoutHeight = layout.getHeight() + px(17); } } if (layoutRealWidth < timeWidth) { layoutRealWidth = timeWidth; } if (isForwarded) { layoutHeight += px(19) * 2; forwardOffset = (int) forwardingPaintBase.measureText("From "); layoutRealWidth = (int) Math.max(layoutRealWidth, forwardingPaintBase.measureText("Forwarded message")); forwarderNameMeasured = TextUtils.ellipsize( forwarderName, senderPaintBase, desiredWidth - forwardOffset, TextUtils.TruncateAt.END) .toString(); layoutRealWidth = (int) Math.max( layoutRealWidth, forwardOffset + senderPaintBase.measureText(forwarderNameMeasured)); } if (isGroup && !isOut && !isForwarded) { layoutHeight += px(19); senderNameMeasured = TextUtils.ellipsize(senderName, senderPaintBase, desiredWidth, TextUtils.TruncateAt.END) .toString(); int width = (int) senderPaintBase.measureText(senderNameMeasured); layoutRealWidth = Math.max(layoutRealWidth, width); } Logger.d(TAG, "Build layout end"); }