|  | /* | 
|  | * Copyright (C) 2017 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | package com.android.server.timezone; | 
|  |  | 
|  | import com.android.server.EventLogTags; | 
|  |  | 
|  | import android.app.timezone.RulesUpdaterContract; | 
|  | import android.content.BroadcastReceiver; | 
|  | import android.content.Context; | 
|  | import android.content.Intent; | 
|  | import android.content.IntentFilter; | 
|  | import android.os.PatternMatcher; | 
|  | import android.os.UserHandle; | 
|  | import android.util.Slog; | 
|  |  | 
|  | /** | 
|  | * The bona fide implementation of {@link IntentHelper}. | 
|  | */ | 
|  | final class IntentHelperImpl implements IntentHelper { | 
|  |  | 
|  | private final static String TAG = "timezone.IntentHelperImpl"; | 
|  |  | 
|  | private final Context mContext; | 
|  | private String mUpdaterAppPackageName; | 
|  |  | 
|  | IntentHelperImpl(Context context) { | 
|  | mContext = context; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void initialize(String updaterAppPackageName, String dataAppPackageName, | 
|  | PackageTracker packageTracker) { | 
|  | mUpdaterAppPackageName = updaterAppPackageName; | 
|  |  | 
|  | // Register for events of interest. | 
|  |  | 
|  | // The intent filter that triggers when package update events happen that indicate there may | 
|  | // be work to do. | 
|  | IntentFilter packageIntentFilter = new IntentFilter(); | 
|  |  | 
|  | packageIntentFilter.addDataScheme("package"); | 
|  | packageIntentFilter.addDataSchemeSpecificPart( | 
|  | updaterAppPackageName, PatternMatcher.PATTERN_LITERAL); | 
|  | packageIntentFilter.addDataSchemeSpecificPart( | 
|  | dataAppPackageName, PatternMatcher.PATTERN_LITERAL); | 
|  |  | 
|  | // ACTION_PACKAGE_ADDED is fired when a package is upgraded or downgraded (in addition to | 
|  | // ACTION_PACKAGE_REMOVED and ACTION_PACKAGE_REPLACED). A system/priv-app can never be | 
|  | // removed entirely so we do not need to trigger on ACTION_PACKAGE_REMOVED or | 
|  | // ACTION_PACKAGE_FULLY_REMOVED. | 
|  | packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); | 
|  |  | 
|  | // ACTION_PACKAGE_CHANGED is used when a package is disabled / re-enabled. It is not | 
|  | // strictly necessary to trigger on this but it won't hurt anything and may catch some cases | 
|  | // where a package has changed while disabled. | 
|  | // Note: ACTION_PACKAGE_CHANGED is not fired when updating a suspended app, but | 
|  | // ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and ACTION_PACKAGE_REPLACED are (and the app | 
|  | // is left in an unsuspended state after this). | 
|  | packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); | 
|  |  | 
|  | // We do not register for ACTION_PACKAGE_RESTARTED because it doesn't imply an update. | 
|  | // We do not register for ACTION_PACKAGE_DATA_CLEARED because the updater / data apps are | 
|  | // not expected to need local data. | 
|  |  | 
|  | Receiver packageUpdateReceiver = new Receiver(packageTracker); | 
|  | mContext.registerReceiverAsUser( | 
|  | packageUpdateReceiver, UserHandle.SYSTEM, packageIntentFilter, | 
|  | null /* broadcastPermission */, null /* default handler */); | 
|  | } | 
|  |  | 
|  | /** Sends an intent to trigger an update check. */ | 
|  | @Override | 
|  | public void sendTriggerUpdateCheck(CheckToken checkToken) { | 
|  | RulesUpdaterContract.sendBroadcast( | 
|  | mContext, mUpdaterAppPackageName, checkToken.toByteArray()); | 
|  | EventLogTags.writeTimezoneTriggerCheck(checkToken.toString()); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public synchronized void scheduleReliabilityTrigger(long minimumDelayMillis) { | 
|  | TimeZoneUpdateIdler.schedule(mContext, minimumDelayMillis); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public synchronized void unscheduleReliabilityTrigger() { | 
|  | TimeZoneUpdateIdler.unschedule(mContext); | 
|  | } | 
|  |  | 
|  | private static class Receiver extends BroadcastReceiver { | 
|  | private final PackageTracker mPackageTracker; | 
|  |  | 
|  | private Receiver(PackageTracker packageTracker) { | 
|  | mPackageTracker = packageTracker; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void onReceive(Context context, Intent intent) { | 
|  | Slog.d(TAG, "Received intent: " + intent.toString()); | 
|  | mPackageTracker.triggerUpdateIfNeeded(true /* packageChanged */); | 
|  | } | 
|  | } | 
|  | } |