/** * Refreshes the current progress value displayed by this progress bar with respect to UI thread, * so this can be also called from the background thread. * <p> * If called from the UI thread, {@link #onRefreshProgress(int, int, boolean)} will be called * immediately, otherwise to refresh progress will be posted runnable. * * @param id One of {@link android.R.id#progress} or {@link android.R.id#secondaryProgress}. * @param progress The progress value to be refreshed. */ @AnyThread @SuppressWarnings("WrongThread") final synchronized void refreshProgress(int id, int progress) { if (mUiThreadId == Thread.currentThread().getId()) { onRefreshProgress(id, progress, true); return; } if (mRefreshProgressRunnable == null) { this.mRefreshProgressRunnable = new RefreshProgressRunnable(); } final RefreshData refreshData = RefreshData.obtain(id, progress); mRefreshProgressRunnable.refreshData.add(refreshData); if ((mPrivateFlags & PrivateFlags.PFLAG_ATTACHED_TO_WINDOW) != 0 && (mPrivateFlags & PFLAG_REFRESH_PROGRESS_POSTED) == 0) { post(mRefreshProgressRunnable); this.updatePrivateFlags(PFLAG_REFRESH_PROGRESS_POSTED, true); } }
@AnyThread public static HandlerType notifyComponents(@NonNull Context context, @NonNull Intent intent) { boolean handled = LocalBroadcastManager.getInstance(context).sendBroadcast(intent); if (handled) { return HandlerType.COMPONENT; } final PackageManager packageManager = context.getPackageManager(); if (intent.resolveActivity(packageManager) != null) { context.startActivity(intent); return HandlerType.ACTIVITY; } return HandlerType.NONE; }
/** * Shut down the renderer when you're finished. */ @Override @AnyThread public void shutdown() { synchronized (this) { if (!isRunning()) { Log.d(TAG, "requesting shutdown..."); renderHandler.removeCallbacks(this); renderHandler.postAtFrontOfQueue(() -> { Log.i(TAG, "shutting down"); synchronized (this) { droppedFrameLogger = null; yuvInAlloc.destroy(); rgbInAlloc.destroy(); rgbOutAlloc.destroy(); yuvToRGBScript.destroy(); if (renderThread != null) { renderThread.quitSafely(); } } }); renderHandler = null; } } }
/** Saves a {@link FirefoxAccountSession} to be restored with {@link #loadSession()}. */ @AnyThread void saveSession(@NonNull final FirefoxAccountSession session) { final FirefoxAccount account = session.firefoxAccount; sharedPrefs.edit() .putInt(KEY_VERSION, STORE_VERSION) .putString(KEY_EMAIL, account.email) .putString(KEY_UID, account.uid) .putString(KEY_STATE_LABEL, account.accountState.getStateLabel().name()) .putString(KEY_STATE_JSON, account.accountState.toJSONObject().toJSONString()) // Future builds can change the endpoints in their config so we only store the label // so we can pull in the latest endpoints. .putString(KEY_ENDPOINT_CONFIG_LABEL, account.endpointConfig.label) .putString(KEY_APPLICATION_NAME, session.applicationName) .apply(); }
/** * Runs the given {@link Request} if no other requests in the given request type is already * running. * <p> * If run, the request will be run in the current thread. * * @param type The type of the request. * @param request The request to run. * @return True if the request is run, false otherwise. */ @SuppressWarnings("WeakerAccess") @AnyThread public boolean runIfNotRunning(@NonNull RequestType type, @NonNull Request request) { boolean hasListeners = !mListeners.isEmpty(); StatusReport report = null; synchronized (mLock) { RequestQueue queue = mRequestQueues[type.ordinal()]; if (queue.mRunning != null) { return false; } queue.mRunning = request; queue.mStatus = Status.RUNNING; queue.mFailed = null; queue.mLastError = null; if (hasListeners) { report = prepareStatusReportLocked(); } } if (report != null) { dispatchReport(report); } final RequestWrapper wrapper = new RequestWrapper(request, this, type); wrapper.run(); return true; }
@AnyThread @VisibleForTesting void recordResult(@NonNull RequestWrapper wrapper, @Nullable Throwable throwable) { StatusReport report = null; final boolean success = throwable == null; boolean hasListeners = !mListeners.isEmpty(); synchronized (mLock) { RequestQueue queue = mRequestQueues[wrapper.mType.ordinal()]; queue.mRunning = null; queue.mLastError = throwable; if (success) { queue.mFailed = null; queue.mStatus = Status.SUCCESS; } else { queue.mFailed = wrapper; queue.mStatus = Status.FAILED; } if (hasListeners) { report = prepareStatusReportLocked(); } } if (report != null) { dispatchReport(report); } }
@AnyThread public static void loadData(final int page, final Object param, final LoadDataCallback cb) { sExecutor.execute(new Runnable() { @Override public void run() { final BaseResult<Item> result = loadDataSync(page, param); sUiHandler.post(new Runnable() { @Override public void run() { if (cb != null) { if (result != null) { cb.onLoadSuccess(page, result.getData(), result.isPageMore()); } else { cb.onLoadFailed(page); } } } }); } }); }
/** * Returns the current storage status for DVR recordings. * * @return {@link StorageStatus} */ @AnyThread public @StorageStatus int getDvrStorageStatus() { MountedStorageStatus status = mMountedStorageStatus; if (status.mStorageMountedDir == null) { return STORAGE_STATUS_MISSING; } if (CommonFeatures.FORCE_RECORDING_UNTIL_NO_SPACE.isEnabled(mContext)) { return STORAGE_STATUS_OK; } if (status.mStorageMountedCapacity < MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES) { return STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL; } try { StatFs statFs = new StatFs(status.mStorageMountedDir.toString()); if (statFs.getAvailableBytes() < MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES) { return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT; } } catch (IllegalArgumentException e) { // In rare cases, storage status change was not notified yet. SoftPreconditions.checkState(false); return STORAGE_STATUS_FREE_SPACE_INSUFFICIENT; } return STORAGE_STATUS_OK; }
/** * Set the color stops used for the heat map's gradient. There needs to be at least 2 stops * and there should be one at a position of 0 and one at a position of 1. * @param stops A map from stop positions (as fractions of the width in [0,1]) to ARGB colors. */ @AnyThread public void setColorStops(Map<Float, Integer> stops) { if (stops.size() < 2) throw new IllegalArgumentException("There must be at least 2 color stops"); colors = new int[stops.size()]; positions = new float[stops.size()]; int i = 0; for (Float key : stops.keySet()) { colors[i] = stops.get(key); positions[i] = key; i++; } if (!mTransparentBackground) mBackground.setColor(colors[0]); }
@AnyThread @SuppressWarnings("WrongThread") private float getScale() { if (mMaxWidth == null || mMaxHeight == null) return 1.0f; float sourceRatio = getWidth() / getHeight(); float targetRatio = mMaxWidth / mMaxHeight; float scale; if (sourceRatio < targetRatio) { scale = getWidth() / ((float)mMaxWidth); } else { scale = getHeight() / ((float)mMaxHeight); } return scale; }
@AnyThread @SuppressLint("WrongThread") private void redrawShadow(int width, int height) { mRenderBoundaries[0] = 10000; mRenderBoundaries[1] = 10000; mRenderBoundaries[2] = 0; mRenderBoundaries[3] = 0; if (mUseDrawingCache) mShadow = getDrawingCache(); else mShadow = Bitmap.createBitmap(getDrawingWidth(), getDrawingHeight(), Bitmap.Config.ARGB_8888); Canvas shadowCanvas = new Canvas(mShadow); drawTransparent(shadowCanvas, width, height); }
@AnyThread @NonNull private AuthState readState() { mPrefsLock.lock(); try { String currentState = mPrefs.getString(KEY_STATE, null); if (currentState == null) { return new AuthState(); } try { return AuthState.jsonDeserialize(currentState); } catch (JSONException ex) { Log.w(TAG, "Failed to deserialize stored auth state - discarding"); return new AuthState(); } } finally { mPrefsLock.unlock(); } }
@AnyThread private void writeState(@Nullable AuthState state) { mPrefsLock.lock(); try { SharedPreferences.Editor editor = mPrefs.edit(); if (state == null) { editor.remove(KEY_STATE); } else { editor.putString(KEY_STATE, state.jsonSerializeString()); } if (!editor.commit()) { throw new IllegalStateException("Failed to write state to shared prefs"); } } finally { mPrefsLock.unlock(); } }
@AnyThread @Override public void onError(final Exception e) { runOnUiThread(() -> { // a 5xx error is not the fault of this app. Nothing we can do about it, so it does not // make sense to send an error report. Just notify the user // Also, we treat an invalid response the same as a (temporary) connection error if (e instanceof OsmConnectionException || e instanceof OsmApiReadResponseException) { Toast.makeText(MainActivity.this,R.string.download_server_error, Toast.LENGTH_LONG).show(); } else { crashReportExceptionHandler.askUserToSendErrorReport(MainActivity.this, R.string.download_error, e); } }); }
@AnyThread @Override public void onQuestsCreated(final Collection<? extends Quest> quests, final QuestGroup group) { runOnUiThread(() -> mapFragment.addQuests(quests, group)); // to recreate element geometry of selected quest (if any) after recreation of activity if(getQuestDetailsFragment() != null) { for (Quest q : quests) { if (isQuestDetailsCurrentlyDisplayedFor(q.getId(), group)) { questController.retrieve(group, q.getId()); return; } } } }
@AnyThread private void writeState(@Nullable AuthState state) { mPrefsLock.lock(); try { if (state == null) { if (!mPrefs.edit().remove(KEY_STATE).commit()) { throw new IllegalStateException("Failed to write state to shared prefs"); } } else { if(!mPrefs.edit().putString(KEY_STATE, state.jsonSerializeString()).commit()) { throw new IllegalStateException("Failed to write state to shared prefs"); } } } finally { mPrefsLock.unlock(); } }
@Override @AnyThread public synchronized void setRsRenderer(RsRenderer rsRenderer) { if (isRunning()) { this.rsRenderer = rsRenderer; Log.i(TAG, "updating RsRenderer to \"" + rsRenderer.getName() + "\""); totalFrames = 0; totalDropped = 0; if (droppedFrameLogger != null) { droppedFrameLogger.clear(); } } }
/** * Check if this renderer is still running or has been shutdown. * * @return true if we're running, else false */ @Override @AnyThread public synchronized boolean isRunning() { if (renderHandler == null) { Log.w(TAG, "renderer was already shut down"); return false; } return true; }
/** * Set the output surface to consume the stream of edited camera frames. This is probably * from a SurfaceView or TextureView. Please make sure it's valid. * * @param outputSurface a valid surface to consume a stream of edited frames from the camera */ @AnyThread @Override public synchronized void setOutputSurface(Surface outputSurface) { if (isRunning()) { if (!outputSurface.isValid()) { throw new IllegalArgumentException("output was invalid"); } rgbOutAlloc.setSurface(outputSurface); outputSurfaceIsSet = true; Log.d(TAG, "output surface was set"); } }
/** * Converts source rectangle from tile, which treats the image file as if it were in the correct orientation already, * to the rectangle of the image that needs to be loaded. */ @SuppressWarnings("SuspiciousNameCombination") @AnyThread private void fileSRect(Rect sRect, Rect target) { if (getRequiredRotation() == 0) { target.set(sRect); } else if (getRequiredRotation() == 90) { target.set(sRect.top, sHeight - sRect.right, sRect.bottom, sHeight - sRect.left); } else if (getRequiredRotation() == 180) { target.set(sWidth - sRect.right, sHeight - sRect.bottom, sWidth - sRect.left, sHeight - sRect.top); } else { target.set(sWidth - sRect.bottom, sRect.left, sWidth - sRect.top, sRect.right); } }
/** * Determines the rotation to be applied to tiles, based on EXIF orientation or chosen setting. */ @AnyThread private int getRequiredRotation() { if (orientation == ORIENTATION_USE_EXIF) { return sOrientation; } else { return orientation; } }
/** * Debug logger */ @AnyThread private void debug(String message, Object... args) { if (debug) { Log.d(TAG, String.format(message, args)); } }
/** * @throws FailedToLoadSessionException if we're unable to load the account. * @return a FirefoxAccount. */ @NonNull @AnyThread FirefoxAccountSession loadSession() throws FailedToLoadSessionException { if (sharedPrefs.getInt(KEY_VERSION, -1) < 0) { throw new FailedToLoadSessionException("account does not exist"); } final State state; try { final StateLabel stateLabel = State.StateLabel.valueOf(sharedPrefs.getString(KEY_STATE_LABEL, null)); final ExtendedJSONObject stateJSON = new ExtendedJSONObject(sharedPrefs.getString(KEY_STATE_JSON, null)); state = StateFactory.fromJSONObject(stateLabel, stateJSON); } catch (final NoSuchAlgorithmException | IOException | NonObjectJSONException | InvalidKeySpecException | IllegalArgumentException e) { throw new FailedToLoadSessionException("unable to restore account state", e); } final String endpointConfigLabel = sharedPrefs.getString(KEY_ENDPOINT_CONFIG_LABEL, ""); final FirefoxAccountEndpointConfig endpointConfig; switch (endpointConfigLabel) { // We should probably use enums over Strings, but it wasn't worth my time. case LABEL_STABLE_DEV: endpointConfig = FirefoxAccountEndpointConfig.getStableDev(); break; case LABEL_LATEST_DEV: endpointConfig = FirefoxAccountEndpointConfig.getLatestDev(); break; case LABEL_STAGE: endpointConfig = FirefoxAccountEndpointConfig.getStage(); break; case LABEL_PRODUCTION: endpointConfig = FirefoxAccountEndpointConfig.getProduction(); break; default: throw new FailedToLoadSessionException("unable to restore account - unknown endpoint label: " + endpointConfigLabel); } final String email = sharedPrefs.getString(KEY_EMAIL, null); final String uid = sharedPrefs.getString(KEY_UID, null); final FirefoxAccount firefoxAccount = new FirefoxAccount(email, uid, state, endpointConfig); final String applicationName = sharedPrefs.getString(KEY_APPLICATION_NAME, null); return new FirefoxAccountSession(firefoxAccount, applicationName); }
/** Removes any saved {@link FirefoxAccountSession}. */ @AnyThread void deleteStoredSession() { // Alternatively, we could call `sharedPrefs.edit().clear()`, but that's fragile, e.g. if we // started to store other metadata in here we wouldn't want to clear on account removal. final SharedPreferences.Editor editor = sharedPrefs.edit(); for (final String key : KEYS_TO_CLEAR_ON_ACCOUNT_REMOVAL) { editor.remove(key); } editor.apply(); }
@AnyThread @Override public void goToLogin() { runOnUiThread(() -> { startActivity(new Intent(this, LoginActivity.class)); finish(); }); }
@AnyThread @Override public void goToMain() { runOnUiThread(() -> { startActivity(new Intent(this, MainActivity.class)); finish(); }); }
@AnyThread @Override public void show() { final Params p = new Params(mStart, mEnd); mStart = null; mEnd = null; mHandler.removeMessages(MSG_SHOW); mHandler.obtainMessage(MSG_SHOW, p).sendToTarget(); }
@AnyThread private static Moonlight encrypt(String key, Moonlight moonlight) { String[] metadata = getMetadata(moonlight); if (key != null) { try { if (metadata[0] != null) { moonlight.setTitle(AESUtils.encrypt(key, metadata[0])); } if (metadata[1] != null) { moonlight.setContent(AESUtils.encrypt(key, metadata[1])); } if (metadata[2] != null) { moonlight.setImageUrl(AESUtils.encrypt(key, metadata[2])); } if (metadata[3] != null) { moonlight.setAudioUrl(AESUtils.encrypt(key, metadata[3])); } if (metadata[4] != null) { moonlight.setImageName(AESUtils.encrypt(key, metadata[4])); } if (metadata[5] != null) { moonlight.setAudioName(AESUtils.encrypt(key, metadata[5])); } return moonlight; } catch (Exception e) { e.printStackTrace(); } } return null; }
@AnyThread private static Moonlight decrypt(String key, Moonlight moonlight) { String[] metadata = getMetadata(moonlight); if (key != null) { try { if (metadata[0] != null) { moonlight.setTitle(AESUtils.decrypt(key, metadata[0])); } if (metadata[1] != null) { moonlight.setContent(AESUtils.decrypt(key, metadata[1])); } if (metadata[2] != null) { moonlight.setImageUrl(AESUtils.decrypt(key, metadata[2])); } if (metadata[3] != null) { moonlight.setAudioUrl(AESUtils.decrypt(key, metadata[3])); } if (metadata[4] != null) { moonlight.setImageName(AESUtils.decrypt(key, metadata[4])); } if (metadata[5] != null) { moonlight.setAudioName(AESUtils.decrypt(key, metadata[5])); } return moonlight; } catch (Exception e) { e.printStackTrace(); } } return null; }
/** * Set the blur factor for the heat map. Must be between 0 and 1. * @param blur The blur factor */ @AnyThread public void setBlur(double blur) { if (blur > 1.0 || blur < 0.0) throw new IllegalArgumentException("Blur must be between 0 and 1."); mBlur = blur; }
@AnyThread @SuppressLint("WrongThread") private int getDrawingWidth() { if (mMaxWidth == null) return getWidth(); return Math.min(calcMaxWidth(), getWidth()); }
@AnyThread @SuppressLint("WrongThread") private int getDrawingHeight() { if (mMaxHeight == null) return getHeight(); return Math.min(calcMaxHeight(), getHeight()); }
/** * If needed, refresh the palette. */ @AnyThread private void tryRefresh(boolean forceRefresh, int width, int height) { if (forceRefresh || needsRefresh) { Bitmap bit = Bitmap.createBitmap(256, 1, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bit); LinearGradient grad; grad = new LinearGradient(0, 0, 256, 1, colors, positions, Shader.TileMode.CLAMP); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setShader(grad); canvas.drawLine(0, 0, 256, 1, paint); palette = new int[256]; bit.getPixels(palette, 0, 256, 0, 0, 256, 1); if (dataModified) { data.clear(); data.addAll(dataBuffer); dataBuffer.clear(); dataModified = false; } redrawShadow(width, height); } else if (sizeChange) { redrawShadow(width, height); } needsRefresh = false; sizeChange = false; }
/** * Draw a radial gradient at a given location. Only draws in black with the gradient being only * in transparency. * * @param canvas Canvas to draw into. * @param x The x location to draw the point. * @param y The y location to draw the point. * @param radius The radius (in pixels) of the point. * @param blurFactor A factor to scale the circles width by. * @param alpha The transparency of the gradient. */ @AnyThread private void drawDataPoint(Canvas canvas, float x, float y, double radius, double blurFactor, double alpha) { if (blurFactor == 1) { canvas.drawCircle(x, y, (float)radius, mBlack); } else { //create a radial gradient at the requested position with the requested size RadialGradient gradient = new RadialGradient(x, y, (float)(radius * blurFactor), new int[] { Color.argb((int)(alpha * 255), 0, 0, 0), Color.argb(0, 0, 0, 0) }, null, Shader.TileMode.CLAMP); mFill.setShader(gradient); canvas.drawCircle(x, y, (float)(2 * radius), mFill); } }
@AnyThread private void drawNewMap() { map.clearData(); Random rand = new Random(); //add 20 random points of random intensity for (int i = 0; i < 20; i++) { HeatMap.DataPoint point = new HeatMap.DataPoint(clamp(rand.nextFloat(), 0.0f, 1.0f), clamp(rand.nextFloat(), 0.0f, 1.0f), clamp(rand.nextDouble(), 0.0, 100.0)); map.addData(point); } }
@AnyThread public static AuthStateManager getInstance(@NonNull Context context) { AuthStateManager manager = INSTANCE_REF.get().get(); if (manager == null) { manager = new AuthStateManager(context.getApplicationContext()); INSTANCE_REF.set(new WeakReference<>(manager)); } return manager; }