• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.N;
4 import static android.os.Build.VERSION_CODES.O;
5 import static android.os.Build.VERSION_CODES.P;
6 import static org.robolectric.RuntimeEnvironment.getApiLevel;
7 import static org.robolectric.util.reflector.Reflector.reflector;
8 
9 import android.content.ClipData;
10 import android.content.ClipDescription;
11 import android.content.ClipboardManager;
12 import android.content.ClipboardManager.OnPrimaryClipChangedListener;
13 import android.os.SystemClock;
14 import java.util.Collection;
15 import java.util.concurrent.CopyOnWriteArrayList;
16 import org.robolectric.annotation.Implementation;
17 import org.robolectric.annotation.Implements;
18 import org.robolectric.annotation.RealObject;
19 import org.robolectric.annotation.Resetter;
20 import org.robolectric.util.ReflectionHelpers;
21 import org.robolectric.util.ReflectionHelpers.ClassParameter;
22 import org.robolectric.util.reflector.ForType;
23 
24 @SuppressWarnings("UnusedDeclaration")
25 @Implements(ClipboardManager.class)
26 public class ShadowClipboardManager {
27   private static final Collection<OnPrimaryClipChangedListener> listeners =
28       new CopyOnWriteArrayList<OnPrimaryClipChangedListener>();
29   private static ClipData clip;
30   @RealObject private ClipboardManager realClipboardManager;
31 
32   @Resetter
reset()33   public static void reset() {
34     clip = null;
35     listeners.clear();
36   }
37 
38   @Implementation(minSdk = P)
clearPrimaryClip()39   protected void clearPrimaryClip() {
40     setPrimaryClip(null);
41   }
42 
43   @Implementation
getPrimaryClip()44   protected ClipData getPrimaryClip() {
45     return clip;
46   }
47 
48   @Implementation
setPrimaryClip(ClipData clip)49   protected void setPrimaryClip(ClipData clip) {
50     if (getApiLevel() >= O) {
51       if (clip != null) {
52         final ClipDescription description = clip.getDescription();
53         if (description != null) {
54           final long currentTimeMillis = SystemClock.uptimeMillis();
55           ReflectionHelpers.callInstanceMethod(
56               ClipDescription.class,
57               description,
58               "setTimestamp",
59               ClassParameter.from(long.class, currentTimeMillis));
60         }
61       }
62     }
63     if (getApiLevel() >= N) {
64       if (clip != null) {
65         clip.prepareToLeaveProcess(true);
66       }
67     } else {
68       if (clip != null) {
69         ReflectionHelpers.callInstanceMethod(ClipData.class, clip, "prepareToLeaveProcess");
70       }
71     }
72 
73     this.clip = clip;
74 
75     for (OnPrimaryClipChangedListener listener : listeners) {
76       listener.onPrimaryClipChanged();
77     }
78   }
79 
80   @Implementation
getPrimaryClipDescription()81   protected ClipDescription getPrimaryClipDescription() {
82     return clip == null ? null : clip.getDescription();
83   }
84 
85   @Implementation
hasPrimaryClip()86   protected boolean hasPrimaryClip() {
87     return clip != null;
88   }
89 
90   @Implementation
addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener)91   protected void addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
92     listeners.add(listener);
93   }
94 
95   @Implementation
removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener)96   protected void removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
97     listeners.remove(listener);
98   }
99 
100   @Implementation
setText(CharSequence text)101   protected void setText(CharSequence text) {
102     setPrimaryClip(ClipData.newPlainText(null, text));
103   }
104 
105   @Implementation
hasText()106   protected boolean hasText() {
107     CharSequence text = reflector(ClipboardManagerReflector.class, realClipboardManager).getText();
108     return text != null && text.length() > 0;
109   }
110 
111   @ForType(ClipboardManager.class)
112   interface ClipboardManagerReflector {
getText()113     CharSequence getText();
114   }
115 }
116