1f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang/* 2f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Copyright (C) 2012 Google Inc. 3f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed to The Android Open Source Project. 4f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 5f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Licensed under the Apache License, Version 2.0 (the "License"); 6f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * you may not use this file except in compliance with the License. 7f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * You may obtain a copy of the License at 8f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 9f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * http://www.apache.org/licenses/LICENSE-2.0 10f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * 11f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * Unless required by applicable law or agreed to in writing, software 12f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * distributed under the License is distributed on an "AS IS" BASIS, 13f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * See the License for the specific language governing permissions and 15f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang * limitations under the License. 16f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang */ 17f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 185ff63747a1b5c6e2197528972cbc3ba808b09d8dAndy Huangpackage com.android.mail.browse; 19f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 20f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.content.Context; 21afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindypimport android.content.res.Resources; 22afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindypimport android.graphics.Bitmap; 23afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindypimport android.graphics.Canvas; 24f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport android.util.AttributeSet; 25bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huangimport android.view.MotionEvent; 26f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 2723014705ca9872cd5004a1aa76e83ae260165ecaAndy Huangimport com.android.mail.R; 28b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 29632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.LogUtils; 30632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 31f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport java.util.Set; 32f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huangimport java.util.concurrent.CopyOnWriteArraySet; 33f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 34c1fb9a9c2730178105977fca629e80951bfc3cdcAndy Huangpublic class ConversationWebView extends MailWebView implements ScrollNotifier { 35afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp /** The initial delay when rendering in hardware layer. */ 3630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang private final int mWebviewInitialDelay; 37afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 38afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp private Bitmap mBitmap; 39afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp private Canvas mCanvas; 40afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 41afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp private boolean mUseSoftwareLayer; 4230bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang /** 4330bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang * Whether this view is user-visible; we don't bother doing supplemental software drawing 4430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang * if the view is off-screen. 4530bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang */ 4630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang private boolean mVisible; 47afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 48afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp /** {@link Runnable} to be run when the page is rendered in hardware layer. */ 49afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp private final Runnable mNotifyPageRenderedInHardwareLayer = new Runnable() { 50afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp @Override 51afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp public void run() { 52afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp // Switch to hardware layer. 53afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp mUseSoftwareLayer = false; 54afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp destroyBitmap(); 55afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp invalidate(); 56afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 57afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp }; 58afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 59afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp @Override 60afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp public void onDraw(Canvas canvas) { 61afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp // Always render in hardware layer to avoid flicker when switch. 62afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp super.onDraw(canvas); 63afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 6430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang // Render in software layer on top if needed, and we're visible (i.e. it's worthwhile to 6530bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang // do all this) 6630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang if (mUseSoftwareLayer && mVisible && getWidth() > 0 && getHeight() > 0) { 6730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang if (mBitmap == null) { 6830bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang try { 6930bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang // Create an offscreen bitmap. 7030bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565); 7130bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas = new Canvas(mBitmap); 7230bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang } catch (OutOfMemoryError e) { 7330bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang // just give up 7430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mBitmap = null; 7530bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas = null; 7630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mUseSoftwareLayer = false; 7730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang } 7830bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang } 7930bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang 8030bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang if (mBitmap != null) { 8130bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang final int x = getScrollX(); 8230bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang final int y = getScrollY(); 8330bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang 8430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas.save(); 8530bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas.translate(-x, -y); 8630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang super.onDraw(mCanvas); 8730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas.restore(); 8830bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang 8930bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang canvas.drawBitmap(mBitmap, x, y, null /* paint */); 9030bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang } 91afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 92afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 93afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 94afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp @Override 95afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp public void destroy() { 96afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp destroyBitmap(); 9730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang removeCallbacks(mNotifyPageRenderedInHardwareLayer); 98afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 99afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp super.destroy(); 100afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 101afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 102afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp /** 103afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * Destroys the {@link Bitmap} used for software layer. 104afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp */ 105afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp private void destroyBitmap() { 106afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp if (mBitmap != null) { 107afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp mBitmap = null; 10830bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mCanvas = null; 109afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 110afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 111afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 112afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp /** 113afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * Enable this WebView to also draw to an internal software canvas until 11430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang * {@link #onRenderComplete()} is called. The software draw will happen every time 115afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * a normal {@link #onDraw(Canvas)} happens, and will overwrite whatever is normally drawn 116afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * (i.e. drawn in hardware) with the results of software rendering. 117afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * <p> 118afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * This is useful when you know that the WebView draws sooner to a software layer than it does 119afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp * to its normal hardware layer. 120afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp */ 121afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp public void setUseSoftwareLayer(boolean useSoftware) { 122afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp mUseSoftwareLayer = useSoftware; 123afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 124afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp 125afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp /** 12630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang * Notifies the {@link ConversationWebView} that it has become visible. It can use this signal 12730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang * to switch between software and hardware layer. 128afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp */ 12930bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang public void onRenderComplete() { 13030bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang if (mUseSoftwareLayer) { 131afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp // Schedule to switch from software layer to hardware layer in 1s. 13230bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang postDelayed(mNotifyPageRenderedInHardwareLayer, mWebviewInitialDelay); 133afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 134afc9b365dc9199ee9b2a1e598b8f40b3c78b6d9fmindyp } 135f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 13630bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang public void onUserVisibilityChanged(boolean visible) { 13730bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mVisible = visible; 13830bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang } 13930bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang 14023014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang private final int mViewportWidth; 14123014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang private final float mDensity; 14223014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 143f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang private final Set<ScrollListener> mScrollListeners = 144f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang new CopyOnWriteArraySet<ScrollListener>(); 145f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 146632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 147632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * True when WebView is handling a touch-- in between POINTER_DOWN and 148632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * POINTER_UP/POINTER_CANCEL. 149632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 150632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mHandlingTouch; 151ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang private boolean mIgnoringTouch; 152632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 153b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 154632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 155f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang public ConversationWebView(Context c) { 156f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang this(c, null); 157f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 158f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 159f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang public ConversationWebView(Context c, AttributeSet attrs) { 160f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang super(c, attrs); 16123014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 16230bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang final Resources r = getResources(); 16330bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mViewportWidth = r.getInteger(R.integer.conversation_webview_viewport_px); 16430bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mWebviewInitialDelay = r.getInteger(R.integer.webview_initial_delay); 16530bcfe7b69f9d8e0cad2ee62dae9d3571cd0d88bAndy Huang mDensity = r.getDisplayMetrics().density; 166f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 167f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 168f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang @Override 169f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang public void addScrollListener(ScrollListener l) { 170f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang mScrollListeners.add(l); 171f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 172f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 173f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang @Override 174f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang public void removeScrollListener(ScrollListener l) { 175f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang mScrollListeners.remove(l); 176f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 177f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 17856d83850db72592a16f4e6ee9e0d59b60ec0824aMark Wei @Override 179f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang protected void onScrollChanged(int l, int t, int oldl, int oldt) { 180f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang super.onScrollChanged(l, t, oldl, oldt); 181f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 182f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang for (ScrollListener listener : mScrollListeners) { 183bb6f0504c1607c89d9a3dd3e6023f36d61837016Andrew Sapperstein listener.onNotifierScroll(t); 184f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 185f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang } 186f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 187bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang @Override 188bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang public boolean onTouchEvent(MotionEvent ev) { 189632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final int action = ev.getActionMasked(); 190bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang 191632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang switch (action) { 192632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang case MotionEvent.ACTION_DOWN: 193632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mHandlingTouch = true; 194632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang break; 195632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang case MotionEvent.ACTION_POINTER_DOWN: 196632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "WebView disabling intercepts: POINTER_DOWN"); 197632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang requestDisallowInterceptTouchEvent(true); 198632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang break; 199632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang case MotionEvent.ACTION_CANCEL: 200632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang case MotionEvent.ACTION_UP: 201632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mHandlingTouch = false; 202ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang mIgnoringTouch = false; 203632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang break; 204bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang } 205bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang 206ce8565b3605c2ce47c75e259f387cd4955f017daAndy Huang final boolean handled = mIgnoringTouch || super.onTouchEvent(ev); 20702f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 20802f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang return handled; 209632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 210632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 211632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public boolean isHandlingTouch() { 212632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return mHandlingTouch; 213bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huang } 214f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang 21523014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang public int getViewportWidth() { 21623014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang return mViewportWidth; 21723014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang } 21823014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 2192160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang /** 2202160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * Returns the effective width available for HTML content in DP units. This width takes into 2212160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * account the given margin (in screen px) by excluding it. This is not the same as DOM width, 2222160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * since the document is rendered at CSS px={@link #mViewportWidth}. 2232160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * 2242160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * @param sideMarginPx HTML body margin, if any (in screen px) 2252160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang * @return width available for HTML content (in dp) 2262160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang */ 2272160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang public int getWidthInDp(int sideMarginPx) { 2282160d53e6ae0bfb797569d616e735e46c21522ffAndy Huang return (int) ((getWidth() - sideMarginPx * 2) / mDensity); 2294dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang } 2304dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang 23123014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang /** 23223014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang * Similar to {@link #getScale()}, except that it returns the initially expected scale, as 23323014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang * determined by the ratio of actual screen pixels to logical HTML pixels. 23423014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang * <p>This assumes that we are able to control the logical HTML viewport with a meta-viewport 23523014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang * tag. 23623014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang */ 23723014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang public float getInitialScale() { 2384dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang final float scale; 2394dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang if (getSettings().getLoadWithOverviewMode()) { 2404dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang // in overview mode (aka auto-fit mode), the base ratio is screen px : viewport px 2414dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang scale = (float) getWidth() / getViewportWidth(); 2424dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang } else { 2434dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang // in no-zoom mode, the base ratio is just screen px : mdpi css px (i.e. density) 2444dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang scale = mDensity; 2454dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang } 2464dc732387454eef3ee6d89f9fa393630eb6213f9Andy Huang return scale; 24723014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang } 24823014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 24923014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang public int screenPxToWebPx(int screenPx) { 25023014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang return (int) (screenPx / getInitialScale()); 25123014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang } 25223014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 25323014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang public int webPxToScreenPx(int webPx) { 25423014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang return (int) (webPx * getInitialScale()); 25523014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang } 25623014705ca9872cd5004a1aa76e83ae260165ecaAndy Huang 2572b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei public float screenPxToWebPxError(int screenPx) { 2582b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei return screenPx / getInitialScale() - screenPxToWebPx(screenPx); 2592b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei } 2602b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei 2612b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei public float webPxToScreenPxError(int webPx) { 2622b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei return webPx * getInitialScale() - webPxToScreenPx(webPx); 2632b24e995cfcdb6ab0579b2fbcccb399a53632395Mark Wei } 26402f9d18a54072db8d86c524f9c09e508092ddd7cAndy Huang 265f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang} 266