/*
 * Copyright 2018 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 androidx.work.impl.utils;

import static android.os.PowerManager.PARTIAL_WAKE_LOCK;

import android.content.Context;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;

import androidx.work.Logger;

import java.util.WeakHashMap;

/**
 * A common class for creating WakeLocks.
 *
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WakeLocks {

    private static final String TAG = Logger.tagWithPrefix("WakeLocks");

    private static final WeakHashMap<PowerManager.WakeLock, String> sWakeLocks =
            new WeakHashMap<>();

    /**
     * Creates and returns a new WakeLock.
     *
     * @param context The context from which to get the PowerManager
     * @param tag     A descriptive tag for the WakeLock; this method will prefix "WorkManager: "
     *                to it
     * @return A new {@link android.os.PowerManager.WakeLock}
     */
    public static PowerManager.WakeLock newWakeLock(
            @NonNull Context context,
            @NonNull String tag) {
        PowerManager powerManager = (PowerManager) context.getApplicationContext()
                .getSystemService(Context.POWER_SERVICE);

        String tagWithPrefix = "WorkManager: " + tag;
        PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK, tagWithPrefix);
        // Wakelocks are created on the command processor thread, but we check if they are still
        // being held on the main thread.
        synchronized (sWakeLocks) {
            sWakeLocks.put(wakeLock, tagWithPrefix);
        }
        return wakeLock;
    }

    /**
     * Checks to see if there are any {@link PowerManager.WakeLock}s that
     * {@link androidx.work.impl.background.systemalarm.SystemAlarmService} holds when all the
     * pending commands have been drained in the command queue.
     */
    public static void checkWakeLocks() {
        // There is a small chance that while we are checking if all the commands in the queue are
        // drained and wake locks are no longer being held, a new command comes along and we end up
        // with a ConcurrentModificationException. The addition of commands happens on the command
        // processor thread and this check is done on the main thread.
        synchronized (sWakeLocks) {
            for (PowerManager.WakeLock wakeLock : sWakeLocks.keySet()) {
                if (wakeLock.isHeld()) {
                    String message = String.format(
                            "WakeLock held for %s",
                            sWakeLocks.get(wakeLock));
                    Logger.get().warning(TAG, message);
                }
            }
        }
    }

    private WakeLocks() {
    }
}

@@ -887,16 +887,64 @@
 ogger;%0A%0A
+import java.util.HashMap;%0Aimport java.util.Map;%0A
 import j
@@ -2967,48 +2967,417 @@
 ad.%0A
-        synchronized (sWakeLocks) %7B%0A    
+%0A        Map%3CPowerManager.WakeLock, String%3E wakeLocksCopy = new HashMap%3C%3E();%0A        synchronized (sWakeLocks) %7B%0A            // Copy the WakeLocks - otherwise we can get a ConcurrentModificationException if the%0A            // garbage collector kicks in and ends up removing something from the master copy while%0A            // we are iterating over it.%0A            wakeLocksCopy.putAll(sWakeLocks);%0A        %7D%0A%0A
     
@@ -3418,26 +3418,25 @@
 eLock : 
-sW
+w
 akeLocks
 .keySet(
@@ -3427,16 +3427,20 @@
 akeLocks
+Copy
 .keySet(
@@ -3456,20 +3456,16 @@
         
-    
 if (wake
@@ -3493,28 +3493,24 @@
             
-   
- 
 String messa
@@ -3532,99 +3532,41 @@
 mat(
-%0A                            %22WakeLock held for %25s%22,%0A                            sW
+%22WakeLock held for %25s%22, w
 akeLocks
 .get
@@ -3561,16 +3561,20 @@
 akeLocks
+Copy
 .get(wak
@@ -3582,20 +3582,16 @@
 Lock));%0A
-    
         
@@ -3638,26 +3638,8 @@
 e);%0A
-                %7D%0A
     

Copy WeakHashMap keySet before iterating it to prevent CME.