1 /* 2 * Copyright 2018 The Android Open Source Project 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 17 package androidx.work.impl.background.systemalarm; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.support.annotation.NonNull; 22 import android.support.annotation.RestrictTo; 23 import android.support.annotation.WorkerThread; 24 import android.util.Log; 25 26 import androidx.work.impl.constraints.WorkConstraintsTracker; 27 import androidx.work.impl.model.WorkSpec; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * This is a command handler which handles the constraints changed event. 34 * Typically this happens for WorkSpec's for which we have pending alarms. 35 * 36 * @hide 37 */ 38 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 39 class ConstraintsCommandHandler { 40 41 private static final String TAG = "ConstraintsCmdHandler"; 42 43 private final Context mContext; 44 private final int mStartId; 45 private final SystemAlarmDispatcher mDispatcher; 46 private final List<WorkSpec> mEligibleWorkSpecs; 47 private final WorkConstraintsTracker mWorkConstraintsTracker; 48 49 ConstraintsCommandHandler( 50 @NonNull Context context, 51 int startId, 52 @NonNull SystemAlarmDispatcher dispatcher) { 53 54 mContext = context; 55 mStartId = startId; 56 mDispatcher = dispatcher; 57 mWorkConstraintsTracker = new WorkConstraintsTracker(mContext, null); 58 mEligibleWorkSpecs = new ArrayList<>(); 59 } 60 61 @WorkerThread 62 void handleConstraintsChanged() { 63 int schedulerLimit = mDispatcher 64 .getWorkManager() 65 .getConfiguration() 66 .getMaxSchedulerLimit(); 67 68 List<WorkSpec> candidates = mDispatcher.getWorkManager().getWorkDatabase() 69 .workSpecDao() 70 .getEligibleWorkForScheduling(schedulerLimit); 71 72 // Filter candidates that are marked as SCHEDULE_NOT_REQUESTED_AT 73 List<WorkSpec> eligibleWorkSpecs = new ArrayList<>(candidates.size()); 74 for (WorkSpec candidate: candidates) { 75 if (candidate.scheduleRequestedAt != WorkSpec.SCHEDULE_NOT_REQUESTED_YET) { 76 eligibleWorkSpecs.add(candidate); 77 } 78 } 79 80 // Update constraint proxy to potentially disable proxies for previously 81 // completed WorkSpecs. 82 ConstraintProxy.updateAll(mContext, eligibleWorkSpecs); 83 // This needs to be done to populate matching WorkSpec ids in every constraint 84 // controller. 85 mWorkConstraintsTracker.replace(eligibleWorkSpecs); 86 87 for (WorkSpec workSpec : eligibleWorkSpecs) { 88 String workSpecId = workSpec.id; 89 if (!workSpec.hasConstraints() 90 || mWorkConstraintsTracker.areAllConstraintsMet(workSpecId)) { 91 mEligibleWorkSpecs.add(workSpec); 92 } 93 } 94 95 for (WorkSpec workSpec : mEligibleWorkSpecs) { 96 String workSpecId = workSpec.id; 97 Intent intent = CommandHandler.createDelayMetIntent(mContext, workSpecId); 98 Log.d(TAG, String.format( 99 "Creating a delay_met command for workSpec with id (%s)", workSpecId)); 100 mDispatcher.postOnMainThread( 101 new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId)); 102 } 103 mWorkConstraintsTracker.reset(); 104 } 105 } 106