• 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.util.ReflectionHelpers;
20 import org.robolectric.util.ReflectionHelpers.ClassParameter;
21 import org.robolectric.util.reflector.ForType;
22 
23 @SuppressWarnings("UnusedDeclaration")
24 @Implements(ClipboardManager.class)
25 public class ShadowClipboardManager {
26   @RealObject private ClipboardManager realClipboardManager;
27   private final Collection<OnPrimaryClipChangedListener> listeners =
28       new CopyOnWriteArrayList<OnPrimaryClipChangedListener>();
29   private ClipData clip;
30 
31   @Implementation
setPrimaryClip(ClipData clip)32   protected void setPrimaryClip(ClipData clip) {
33     if (getApiLevel() >= O) {
34       if (clip != null) {
35         final ClipDescription description = clip.getDescription();
36         if (description != null) {
37           final long currentTimeMillis = SystemClock.uptimeMillis();
38           ReflectionHelpers.callInstanceMethod(
39               ClipDescription.class,
40               description,
41               "setTimestamp",
42               ClassParameter.from(long.class, currentTimeMillis));
43         }
44       }
45     }
46     if (getApiLevel() >= N) {
47       if (clip != null) {
48         clip.prepareToLeaveProcess(true);
49       }
50     } else {
51       if (clip != null) {
52         ReflectionHelpers.callInstanceMethod(ClipData.class, clip, "prepareToLeaveProcess");
53       }
54     }
55 
56     this.clip = clip;
57 
58     for (OnPrimaryClipChangedListener listener : listeners) {
59       listener.onPrimaryClipChanged();
60     }
61   }
62 
63   @Implementation(minSdk = P)
clearPrimaryClip()64   protected void clearPrimaryClip() {
65     setPrimaryClip(null);
66   }
67 
68   @Implementation
getPrimaryClip()69   protected ClipData getPrimaryClip() {
70     return clip;
71   }
72 
73   @Implementation
getPrimaryClipDescription()74   protected ClipDescription getPrimaryClipDescription() {
75     return clip == null ? null : clip.getDescription();
76   }
77 
78   @Implementation
hasPrimaryClip()79   protected boolean hasPrimaryClip() {
80     return clip != null;
81   }
82 
83   @Implementation
addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener)84   protected void addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
85     listeners.add(listener);
86   }
87 
88   @Implementation
removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener)89   protected void removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
90     listeners.remove(listener);
91   }
92 
93   @Implementation
setText(CharSequence text)94   protected void setText(CharSequence text) {
95     setPrimaryClip(ClipData.newPlainText(null, text));
96   }
97 
98   @Implementation
hasText()99   protected boolean hasText() {
100     CharSequence text = reflector(ClipboardManagerReflector.class, realClipboardManager).getText();
101     return text != null && text.length() > 0;
102   }
103 
104   @ForType(ClipboardManager.class)
105   interface ClipboardManagerReflector {
getText()106     CharSequence getText();
107   }
108 }
109