Home | History | Annotate | Download | only in browse
      1 /*
      2  * Copyright (C) 2013 Google Inc.
      3  * Licensed to The Android Open Source Project.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mail.browse;
     19 
     20 import android.content.Context;
     21 import android.os.Handler;
     22 import android.os.Looper;
     23 import android.util.AttributeSet;
     24 import android.view.MotionEvent;
     25 import android.webkit.WebView;
     26 
     27 import com.android.mail.utils.Clock;
     28 import com.android.mail.utils.LogTag;
     29 import com.android.mail.utils.LogUtils;
     30 import com.android.mail.utils.Throttle;
     31 
     32 /**
     33  * A WebView designed to live within a {@link MessageScrollView}.
     34  */
     35 public class MessageWebView extends WebView implements MessageScrollView.Touchable {
     36 
     37     private static final String LOG_TAG = LogTag.getLogTag();
     38 
     39     private static Handler sMainThreadHandler;
     40 
     41     private boolean mTouched;
     42 
     43     private static final int MIN_RESIZE_INTERVAL = 200;
     44     private static final int MAX_RESIZE_INTERVAL = 300;
     45     private final Clock mClock = Clock.INSTANCE;
     46 
     47     private final Throttle mThrottle = new Throttle("MessageWebView",
     48             new Runnable() {
     49                 @Override public void run() {
     50                     performSizeChangeDelayed();
     51                 }
     52             }, getMainThreadHandler(),
     53             MIN_RESIZE_INTERVAL, MAX_RESIZE_INTERVAL);
     54 
     55     private int mRealWidth;
     56     private int mRealHeight;
     57     private boolean mIgnoreNext;
     58     private long mLastSizeChangeTime = -1;
     59 
     60     public MessageWebView(Context c) {
     61         this(c, null);
     62     }
     63 
     64     public MessageWebView(Context c, AttributeSet attrs) {
     65         super(c, attrs);
     66     }
     67 
     68     @Override
     69     public boolean wasTouched() {
     70         return mTouched;
     71     }
     72 
     73     @Override
     74     public void clearTouched() {
     75         mTouched = false;
     76     }
     77 
     78     @Override
     79     public boolean onTouchEvent(MotionEvent event) {
     80         mTouched = true;
     81         final boolean handled = super.onTouchEvent(event);
     82         LogUtils.d(MessageScrollView.LOG_TAG,"OUT WebView.onTouch, returning handled=%s ev=%s",
     83                 handled, event);
     84         return handled;
     85     }
     86 
     87     @Override
     88     protected void onSizeChanged(int w, int h, int ow, int oh) {
     89         mRealWidth = w;
     90         mRealHeight = h;
     91         final long now = mClock.getTime();
     92         boolean recentlySized = (now - mLastSizeChangeTime < MIN_RESIZE_INTERVAL);
     93 
     94         // It's known that the previous resize event may cause a resize event immediately. If
     95         // this happens sufficiently close to the last resize event, drop it on the floor.
     96         if (mIgnoreNext) {
     97             mIgnoreNext = false;
     98             if (recentlySized) {
     99                     LogUtils.w(LOG_TAG, "Suppressing size change in MessageWebView");
    100                 return;
    101             }
    102         }
    103 
    104         if (recentlySized) {
    105             mThrottle.onEvent();
    106         } else {
    107             // It's been a sufficiently long time - just perform the resize as normal. This should
    108             // be the normal code path.
    109             performSizeChange(ow, oh);
    110         }
    111     }
    112 
    113     private void performSizeChange(int ow, int oh) {
    114         super.onSizeChanged(mRealWidth, mRealHeight, ow, oh);
    115         mLastSizeChangeTime = mClock.getTime();
    116     }
    117 
    118     private void performSizeChangeDelayed() {
    119         mIgnoreNext = true;
    120         performSizeChange(getWidth(), getHeight());
    121     }
    122 
    123     /**
    124      * @return a {@link Handler} tied to the main thread.
    125      */
    126     public static Handler getMainThreadHandler() {
    127         if (sMainThreadHandler == null) {
    128             // No need to synchronize -- it's okay to create an extra Handler, which will be used
    129             // only once and then thrown away.
    130             sMainThreadHandler = new Handler(Looper.getMainLooper());
    131         }
    132         return sMainThreadHandler;
    133     }
    134 }
    135