mobile/android/thirdparty/com/squareup/picasso/Dispatcher.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2  * Copyright (C) 2013 Square, Inc.
     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 package com.squareup.picasso;
    18 import android.Manifest;
    19 import android.content.BroadcastReceiver;
    20 import android.content.Context;
    21 import android.content.Intent;
    22 import android.content.IntentFilter;
    23 import android.net.ConnectivityManager;
    24 import android.net.NetworkInfo;
    25 import android.os.Bundle;
    26 import android.os.Handler;
    27 import android.os.HandlerThread;
    28 import android.os.Looper;
    29 import android.os.Message;
    30 import java.util.ArrayList;
    31 import java.util.LinkedHashMap;
    32 import java.util.List;
    33 import java.util.Map;
    34 import java.util.concurrent.ExecutorService;
    36 import static android.content.Context.CONNECTIVITY_SERVICE;
    37 import static android.content.Intent.ACTION_AIRPLANE_MODE_CHANGED;
    38 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
    39 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
    40 import static com.squareup.picasso.BitmapHunter.forRequest;
    42 class Dispatcher {
    43   private static final int RETRY_DELAY = 500;
    44   private static final int AIRPLANE_MODE_ON = 1;
    45   private static final int AIRPLANE_MODE_OFF = 0;
    47   static final int REQUEST_SUBMIT = 1;
    48   static final int REQUEST_CANCEL = 2;
    49   static final int REQUEST_GCED = 3;
    50   static final int HUNTER_COMPLETE = 4;
    51   static final int HUNTER_RETRY = 5;
    52   static final int HUNTER_DECODE_FAILED = 6;
    53   static final int HUNTER_DELAY_NEXT_BATCH = 7;
    54   static final int HUNTER_BATCH_COMPLETE = 8;
    55   static final int NETWORK_STATE_CHANGE = 9;
    56   static final int AIRPLANE_MODE_CHANGE = 10;
    58   private static final String DISPATCHER_THREAD_NAME = "Dispatcher";
    59   private static final int BATCH_DELAY = 200; // ms
    61   final DispatcherThread dispatcherThread;
    62   final Context context;
    63   final ExecutorService service;
    64   final Downloader downloader;
    65   final Map<String, BitmapHunter> hunterMap;
    66   final Handler handler;
    67   final Handler mainThreadHandler;
    68   final Cache cache;
    69   final Stats stats;
    70   final List<BitmapHunter> batch;
    71   final NetworkBroadcastReceiver receiver;
    73   NetworkInfo networkInfo;
    74   boolean airplaneMode;
    76   Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
    77       Downloader downloader, Cache cache, Stats stats) {
    78     this.dispatcherThread = new DispatcherThread();
    79     this.dispatcherThread.start();
    80     this.context = context;
    81     this.service = service;
    82     this.hunterMap = new LinkedHashMap<String, BitmapHunter>();
    83     this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
    84     this.downloader = downloader;
    85     this.mainThreadHandler = mainThreadHandler;
    86     this.cache = cache;
    87     this.stats = stats;
    88     this.batch = new ArrayList<BitmapHunter>(4);
    89     this.airplaneMode = Utils.isAirplaneModeOn(this.context);
    90     this.receiver = new NetworkBroadcastReceiver(this.context);
    91     receiver.register();
    92   }
    94   void shutdown() {
    95     service.shutdown();
    96     dispatcherThread.quit();
    97     receiver.unregister();
    98   }
   100   void dispatchSubmit(Action action) {
   101     handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
   102   }
   104   void dispatchCancel(Action action) {
   105     handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action));
   106   }
   108   void dispatchComplete(BitmapHunter hunter) {
   109     handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
   110   }
   112   void dispatchRetry(BitmapHunter hunter) {
   113     handler.sendMessageDelayed(handler.obtainMessage(HUNTER_RETRY, hunter), RETRY_DELAY);
   114   }
   116   void dispatchFailed(BitmapHunter hunter) {
   117     handler.sendMessage(handler.obtainMessage(HUNTER_DECODE_FAILED, hunter));
   118   }
   120   void dispatchNetworkStateChange(NetworkInfo info) {
   121     handler.sendMessage(handler.obtainMessage(NETWORK_STATE_CHANGE, info));
   122   }
   124   void dispatchAirplaneModeChange(boolean airplaneMode) {
   125     handler.sendMessage(handler.obtainMessage(AIRPLANE_MODE_CHANGE,
   126         airplaneMode ? AIRPLANE_MODE_ON : AIRPLANE_MODE_OFF, 0));
   127   }
   129   void performSubmit(Action action) {
   130     BitmapHunter hunter = hunterMap.get(action.getKey());
   131     if (hunter != null) {
   132       hunter.attach(action);
   133       return;
   134     }
   136     if (service.isShutdown()) {
   137       return;
   138     }
   140     hunter = forRequest(context, action.getPicasso(), this, cache, stats, action, downloader);
   141     hunter.future = service.submit(hunter);
   142     hunterMap.put(action.getKey(), hunter);
   143   }
   145   void performCancel(Action action) {
   146     String key = action.getKey();
   147     BitmapHunter hunter = hunterMap.get(key);
   148     if (hunter != null) {
   149       hunter.detach(action);
   150       if (hunter.cancel()) {
   151         hunterMap.remove(key);
   152       }
   153     }
   154   }
   156   void performRetry(BitmapHunter hunter) {
   157     if (hunter.isCancelled()) return;
   159     if (service.isShutdown()) {
   160       performError(hunter);
   161       return;
   162     }
   164     if (hunter.shouldRetry(airplaneMode, networkInfo)) {
   165       hunter.future = service.submit(hunter);
   166     } else {
   167       performError(hunter);
   168     }
   169   }
   171   void performComplete(BitmapHunter hunter) {
   172     if (!hunter.shouldSkipMemoryCache()) {
   173       cache.set(hunter.getKey(), hunter.getResult());
   174     }
   175     hunterMap.remove(hunter.getKey());
   176     batch(hunter);
   177   }
   179   void performBatchComplete() {
   180     List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch);
   181     batch.clear();
   182     mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
   183   }
   185   void performError(BitmapHunter hunter) {
   186     hunterMap.remove(hunter.getKey());
   187     batch(hunter);
   188   }
   190   void performAirplaneModeChange(boolean airplaneMode) {
   191     this.airplaneMode = airplaneMode;
   192   }
   194   void performNetworkStateChange(NetworkInfo info) {
   195     networkInfo = info;
   196     if (service instanceof PicassoExecutorService) {
   197       ((PicassoExecutorService) service).adjustThreadCount(info);
   198     }
   199   }
   201   private void batch(BitmapHunter hunter) {
   202     if (hunter.isCancelled()) {
   203       return;
   204     }
   205     batch.add(hunter);
   206     if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
   207       handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
   208     }
   209   }
   211   private static class DispatcherHandler extends Handler {
   212     private final Dispatcher dispatcher;
   214     public DispatcherHandler(Looper looper, Dispatcher dispatcher) {
   215       super(looper);
   216       this.dispatcher = dispatcher;
   217     }
   219     @Override public void handleMessage(final Message msg) {
   220       switch (msg.what) {
   221         case REQUEST_SUBMIT: {
   222           Action action = (Action) msg.obj;
   223           dispatcher.performSubmit(action);
   224           break;
   225         }
   226         case REQUEST_CANCEL: {
   227           Action action = (Action) msg.obj;
   228           dispatcher.performCancel(action);
   229           break;
   230         }
   231         case HUNTER_COMPLETE: {
   232           BitmapHunter hunter = (BitmapHunter) msg.obj;
   233           dispatcher.performComplete(hunter);
   234           break;
   235         }
   236         case HUNTER_RETRY: {
   237           BitmapHunter hunter = (BitmapHunter) msg.obj;
   238           dispatcher.performRetry(hunter);
   239           break;
   240         }
   241         case HUNTER_DECODE_FAILED: {
   242           BitmapHunter hunter = (BitmapHunter) msg.obj;
   243           dispatcher.performError(hunter);
   244           break;
   245         }
   246         case HUNTER_DELAY_NEXT_BATCH: {
   247           dispatcher.performBatchComplete();
   248           break;
   249         }
   250         case NETWORK_STATE_CHANGE: {
   251           NetworkInfo info = (NetworkInfo) msg.obj;
   252           dispatcher.performNetworkStateChange(info);
   253           break;
   254         }
   255         case AIRPLANE_MODE_CHANGE: {
   256           dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
   257           break;
   258         }
   259         default:
   260           Picasso.HANDLER.post(new Runnable() {
   261             @Override public void run() {
   262               throw new AssertionError("Unknown handler message received: " + msg.what);
   263             }
   264           });
   265       }
   266     }
   267   }
   269   static class DispatcherThread extends HandlerThread {
   270     DispatcherThread() {
   271       super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
   272     }
   273   }
   275   private class NetworkBroadcastReceiver extends BroadcastReceiver {
   276     private static final String EXTRA_AIRPLANE_STATE = "state";
   278     private final ConnectivityManager connectivityManager;
   280     NetworkBroadcastReceiver(Context context) {
   281       connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
   282     }
   284     void register() {
   285       boolean shouldScanState = service instanceof PicassoExecutorService && //
   286           Utils.hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
   287       IntentFilter filter = new IntentFilter();
   288       filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
   289       if (shouldScanState) {
   290         filter.addAction(CONNECTIVITY_ACTION);
   291       }
   292       context.registerReceiver(this, filter);
   293     }
   295     void unregister() {
   296       context.unregisterReceiver(this);
   297     }
   299     @Override public void onReceive(Context context, Intent intent) {
   300       // On some versions of Android this may be called with a null Intent
   301       if (null == intent) {
   302         return;
   303       }
   305       String action = intent.getAction();
   306       Bundle extras = intent.getExtras();
   308       if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
   309         dispatchAirplaneModeChange(extras.getBoolean(EXTRA_AIRPLANE_STATE, false));
   310       } else if (CONNECTIVITY_ACTION.equals(action)) {
   311         dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
   312       }
   313     }
   314   }
   315 }

mercurial