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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial