/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.devsupport;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.view.WindowManager;
import android.widget.FrameLayout;

import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.ReactConstants;

import javax.annotation.Nullable;

/**
 * Helper class for controlling overlay view with FPS and JS FPS info
 * that gets added directly to @{link WindowManager} instance.
 */
/* package */ class DebugOverlayController {

  public static void requestPermission(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      // Get permission to show debug overlay in dev builds.
      if (!Settings.canDrawOverlays(context)) {
        Intent intent = new Intent(
                Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + context.getPackageName()));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        FLog.w(ReactConstants.TAG, "Overlay permissions needs to be granted in order for react native apps to run in dev mode");
        if (canHandleIntent(context, intent)) {
          context.startActivity(intent);
        }
      }
    }
  }

  private static boolean permissionCheck(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      // Get permission to show debug overlay in dev builds.
      if (!Settings.canDrawOverlays(context)) {
        // overlay permission not yet granted
        return false;
      } else {
        return true;
      }
    }
    // on pre-M devices permission needs to be specified in manifest
    return hasPermission(context, Manifest.permission.SYSTEM_ALERT_WINDOW);
  }

  private static boolean hasPermission(Context context, String permission) {
    try {
      PackageInfo info = context.getPackageManager().getPackageInfo(
              context.getPackageName(),
              PackageManager.GET_PERMISSIONS);
      if (info.requestedPermissions != null) {
        for (String p : info.requestedPermissions) {
          if (p.equals(permission)) {
            return true;
          }
        }
      }
    } catch (PackageManager.NameNotFoundException e) {
      FLog.e(ReactConstants.TAG, "Error while retrieving package info", e);
    }
    return false;
  }

  private static boolean canHandleIntent(Context context, Intent intent) {
    PackageManager packageManager = context.getPackageManager();
    return intent.resolveActivity(packageManager) != null;
  }

  private final WindowManager mWindowManager;
  private final ReactContext mReactContext;

  private @Nullable FrameLayout mFPSDebugViewContainer;

  public DebugOverlayController(ReactContext reactContext) {
    mReactContext = reactContext;
    mWindowManager = (WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE);
  }

  public void setFpsDebugViewVisible(boolean fpsDebugViewVisible) {
    if (fpsDebugViewVisible && mFPSDebugViewContainer == null) {
      if (!permissionCheck(mReactContext)) {
        FLog.d(ReactConstants.TAG, "Wait for overlay permission to be set");
        return;
      }
      mFPSDebugViewContainer = new FpsView(mReactContext);
      WindowManager.LayoutParams params = new WindowManager.LayoutParams(
          WindowManager.LayoutParams.MATCH_PARENT,
          WindowManager.LayoutParams.MATCH_PARENT,
          WindowOverlayCompat.TYPE_SYSTEM_OVERLAY,
          WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
              | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
          PixelFormat.TRANSLUCENT);
      mWindowManager.addView(mFPSDebugViewContainer, params);
    } else if (!fpsDebugViewVisible && mFPSDebugViewContainer != null) {
      mFPSDebugViewContainer.removeAllViews();
      mWindowManager.removeView(mFPSDebugViewContainer);
      mFPSDebugViewContainer = null;
    }
  }
}

@@ -661,24 +661,71 @@
 actContext;%0A
+import com.facebook.react.bridge.UiThreadUtil;%0A
 import com.f
@@ -3346,16 +3346,22 @@
 Visible(
+final 
 boolean 
@@ -3379,24 +3379,118 @@
 wVisible) %7B%0A
+    UiThreadUtil.runOnUiThread(new Runnable() %7B%0A      @Override%0A      public void run() %7B%0A    
     if (fpsD
@@ -3538,24 +3538,28 @@
  == null) %7B%0A
+    
       if (!p
@@ -3595,24 +3595,28 @@
 ) %7B%0A        
+    
 FLog.d(React
@@ -3676,24 +3676,28 @@
 %22);%0A        
+ 
+   
 return;%0A    
@@ -3694,26 +3694,34 @@
 turn;%0A      
-%7D%0A
+    %7D%0A    
       mFPSDe
@@ -3769,24 +3769,28 @@
 ext);%0A      
+    
 WindowManage
@@ -3845,16 +3845,18 @@
 Params(%0A
+  
         
@@ -3900,32 +3900,34 @@
 RENT,%0A          
+  
 WindowManager.La
@@ -3943,32 +3943,34 @@
 s.MATCH_PARENT,%0A
+  
           Window
@@ -4006,32 +4006,34 @@
 RLAY,%0A          
+ 
+ 
 WindowManager.La
@@ -4135,16 +4135,18 @@
         
+  
 PixelFor
@@ -4163,16 +4163,20 @@
 UCENT);%0A
+    
       mW
@@ -4229,16 +4229,20 @@
 arams);%0A
+    
     %7D el
@@ -4308,24 +4308,28 @@
 ll) %7B%0A      
+    
 mFPSDebugVie
@@ -4353,24 +4353,28 @@
 AllViews();%0A
+    
       mWindo
@@ -4420,24 +4420,28 @@
 ner);%0A      
+   
+ 
 mFPSDebugVie
@@ -4459,20 +4459,40 @@
 = null;%0A    
-%7D
+    %7D%0A      %7D%0A    %7D);
 %0A  %7D%0A%7D%0A

Fix crash when reloading with Perf Monitor enabled