Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
      4 import static android.os.Build.VERSION_CODES.P;
      5 
      6 import android.hardware.display.DisplayManagerGlobal;
      7 import android.hardware.display.IDisplayManager;
      8 import android.hardware.display.IDisplayManagerCallback;
      9 import android.hardware.display.WifiDisplayStatus;
     10 import android.os.RemoteException;
     11 import android.view.DisplayInfo;
     12 import java.util.ArrayList;
     13 import java.util.List;
     14 import java.util.TreeMap;
     15 import org.robolectric.annotation.Implementation;
     16 import org.robolectric.annotation.Implements;
     17 import org.robolectric.annotation.Resetter;
     18 import org.robolectric.shadow.api.Shadow;
     19 import org.robolectric.util.ReflectionHelpers;
     20 import org.robolectric.util.ReflectionHelpers.ClassParameter;
     21 
     22 @Implements(value = DisplayManagerGlobal.class, isInAndroidSdk = false, minSdk = JELLY_BEAN_MR1)
     23 public class ShadowDisplayManagerGlobal {
     24   private static DisplayManagerGlobal instance;
     25 
     26   private MyDisplayManager mDm;
     27 
     28   @Resetter
     29   public static void reset() {
     30     instance = null;
     31   }
     32 
     33   @Implementation
     34   synchronized public static DisplayManagerGlobal getInstance() {
     35     if (instance == null) {
     36       MyDisplayManager myIDisplayManager = new MyDisplayManager();
     37       IDisplayManager proxy = ReflectionHelpers.createDelegatingProxy(IDisplayManager.class, myIDisplayManager);
     38       instance = ReflectionHelpers.callConstructor(DisplayManagerGlobal.class,
     39           ClassParameter.from(IDisplayManager.class, proxy));
     40       ShadowDisplayManagerGlobal shadow = Shadow.extract(instance);
     41       shadow.mDm = myIDisplayManager;
     42     }
     43     return instance;
     44   }
     45 
     46   @Implementation
     47   protected WifiDisplayStatus getWifiDisplayStatus() {
     48     return new WifiDisplayStatus();
     49   }
     50 
     51   int addDisplay(DisplayInfo displayInfo) {
     52     fixNominalDimens(displayInfo);
     53 
     54     return mDm.addDisplay(displayInfo);
     55   }
     56 
     57   private void fixNominalDimens(DisplayInfo displayInfo) {
     58     int min = Math.min(displayInfo.appWidth, displayInfo.appHeight);
     59     int max = Math.max(displayInfo.appWidth, displayInfo.appHeight);
     60     displayInfo.smallestNominalAppHeight = displayInfo.smallestNominalAppWidth = min;
     61     displayInfo.largestNominalAppHeight = displayInfo.largestNominalAppWidth = max;
     62   }
     63 
     64   void changeDisplay(int displayId, DisplayInfo displayInfo) {
     65     mDm.changeDisplay(displayId, displayInfo);
     66   }
     67 
     68   void removeDisplay(int displayId) {
     69     mDm.removeDisplay(displayId);
     70   }
     71 
     72   private static class MyDisplayManager {
     73     private final TreeMap<Integer, DisplayInfo> displayInfos = new TreeMap<>();
     74     private int nextDisplayId = 0;
     75     private final List<IDisplayManagerCallback> callbacks = new ArrayList<>();
     76 
     77     // @Override
     78     public DisplayInfo getDisplayInfo(int i) throws RemoteException {
     79       DisplayInfo displayInfo = displayInfos.get(i);
     80       return displayInfo == null ? null : new DisplayInfo(displayInfo);
     81     }
     82 
     83     // @Override // todo: use @Implements/@Implementation for signature checking
     84     public int[] getDisplayIds() throws RemoteException {
     85       int[] ids = new int[displayInfos.size()];
     86       int i = 0;
     87       for (Integer displayId : displayInfos.keySet()) {
     88         ids[i++] = displayId;
     89       }
     90       return ids;
     91     }
     92 
     93     // @Override
     94     public void registerCallback(IDisplayManagerCallback iDisplayManagerCallback) throws RemoteException {
     95       this.callbacks.add(iDisplayManagerCallback);
     96     }
     97 
     98     synchronized private int addDisplay(DisplayInfo displayInfo) {
     99       int nextId = nextDisplayId++;
    100       displayInfos.put(nextId, displayInfo);
    101       notifyListeners(nextId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
    102       return nextId;
    103     }
    104 
    105     synchronized private void changeDisplay(int displayId, DisplayInfo displayInfo) {
    106       if (!displayInfos.containsKey(displayId)) {
    107         throw new IllegalStateException("no display " + displayId);
    108       }
    109 
    110       displayInfos.put(displayId, displayInfo);
    111       notifyListeners(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
    112     }
    113 
    114     synchronized private void removeDisplay(int displayId) {
    115       if (!displayInfos.containsKey(displayId)) {
    116         throw new IllegalStateException("no display " + displayId);
    117       }
    118 
    119       displayInfos.remove(displayId);
    120       notifyListeners(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
    121     }
    122 
    123     private void notifyListeners(int nextId, int event) {
    124       for (IDisplayManagerCallback callback : callbacks) {
    125         try {
    126           callback.onDisplayEvent(nextId, event);
    127         } catch (RemoteException e) {
    128           throw new RuntimeException(e);
    129         }
    130       }
    131     }
    132   }
    133 }
    134