blob: 5653cadfa44c09a6ba904fac64d4a6fa650641a1 [file] [log] [blame]
Dianne Hackborn9f531192010-08-04 17:48:03 -07001/**
2 * Copyright (c) 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
19import android.content.Context;
20import android.os.Message;
21import android.os.RemoteException;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.ServiceManager;
Dianne Hackborn9f531192010-08-04 17:48:03 -070025
26import java.util.ArrayList;
27
28/**
29 * Interface to the clipboard service, for placing and retrieving text in
30 * the global clipboard.
31 *
32 * <p>
33 * You do not instantiate this class directly; instead, retrieve it through
34 * {@link android.content.Context#getSystemService}.
35 *
Dianne Hackborn23fdaf62010-08-06 12:16:55 -070036 * <p>
37 * The ClipboardManager API itself is very simple: it consists of methods
38 * to atomically get and set the current primary clipboard data. That data
Dianne Hackborn1040dc42010-08-26 22:11:06 -070039 * is expressed as a {@link ClipData} object, which defines the protocol
Dianne Hackborn23fdaf62010-08-06 12:16:55 -070040 * for data exchange between applications.
41 *
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080042 * <div class="special reference">
43 * <h3>Developer Guides</h3>
44 * <p>For more information about using the clipboard framework, read the
45 * <a href="{@docRoot}guide/topics/clipboard/copy-paste.html">Copy and Paste</a>
46 * developer guide.</p>
47 * </div>
48 *
Dianne Hackborn9f531192010-08-04 17:48:03 -070049 * @see android.content.Context#getSystemService
50 */
51public class ClipboardManager extends android.text.ClipboardManager {
52 private final static Object sStaticLock = new Object();
53 private static IClipboard sService;
54
55 private final Context mContext;
56
57 private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners
58 = new ArrayList<OnPrimaryClipChangedListener>();
59
60 private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener
61 = new IOnPrimaryClipChangedListener.Stub() {
62 public void dispatchPrimaryClipChanged() {
63 mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED);
64 }
65 };
66
67 static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1;
68
69 private final Handler mHandler = new Handler() {
70 @Override
71 public void handleMessage(Message msg) {
72 switch (msg.what) {
73 case MSG_REPORT_PRIMARY_CLIP_CHANGED:
74 reportPrimaryClipChanged();
75 }
76 }
77 };
78
Joe Malin413e9b32011-12-15 15:42:25 -080079 /**
80 * Defines a listener callback that is invoked when the primary clip on the clipboard changes.
81 * Objects that want to register a listener call
82 * {@link android.content.ClipboardManager#addPrimaryClipChangedListener(OnPrimaryClipChangedListener)
83 * addPrimaryClipChangedListener()} with an
84 * object that implements OnPrimaryClipChangedListener.
85 *
86 */
Dianne Hackborn9f531192010-08-04 17:48:03 -070087 public interface OnPrimaryClipChangedListener {
Joe Malin413e9b32011-12-15 15:42:25 -080088
89 /**
90 * Callback that is invoked by {@link android.content.ClipboardManager} when the primary
91 * clip changes.
92 */
Dianne Hackborn9f531192010-08-04 17:48:03 -070093 void onPrimaryClipChanged();
94 }
95
96 static private IClipboard getService() {
97 synchronized (sStaticLock) {
98 if (sService != null) {
99 return sService;
100 }
101 IBinder b = ServiceManager.getService("clipboard");
102 sService = IClipboard.Stub.asInterface(b);
103 return sService;
104 }
105 }
106
107 /** {@hide} */
108 public ClipboardManager(Context context, Handler handler) {
109 mContext = context;
110 }
111
112 /**
113 * Sets the current primary clip on the clipboard. This is the clip that
114 * is involved in normal cut and paste operations.
115 *
116 * @param clip The clipped data item to set.
117 */
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700118 public void setPrimaryClip(ClipData clip) {
Dianne Hackborn9f531192010-08-04 17:48:03 -0700119 try {
Jeff Sharkeya14acd22013-04-02 18:27:45 -0700120 if (clip != null) {
121 clip.prepareToLeaveProcess();
122 }
Dianne Hackborn95d78532013-09-11 09:51:14 -0700123 getService().setPrimaryClip(clip, mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700124 } catch (RemoteException e) {
125 }
126 }
127
128 /**
129 * Returns the current primary clip on the clipboard.
130 */
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700131 public ClipData getPrimaryClip() {
Dianne Hackborn9f531192010-08-04 17:48:03 -0700132 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700133 return getService().getPrimaryClip(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700134 } catch (RemoteException e) {
135 return null;
136 }
137 }
138
139 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700140 * Returns a description of the current primary clip on the clipboard
141 * but not a copy of its data.
142 */
143 public ClipDescription getPrimaryClipDescription() {
144 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700145 return getService().getPrimaryClipDescription(mContext.getOpPackageName());
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700146 } catch (RemoteException e) {
147 return null;
148 }
149 }
150
151 /**
Dianne Hackborn9f531192010-08-04 17:48:03 -0700152 * Returns true if there is currently a primary clip on the clipboard.
153 */
154 public boolean hasPrimaryClip() {
155 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700156 return getService().hasPrimaryClip(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700157 } catch (RemoteException e) {
158 return false;
159 }
160 }
161
162 public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
163 synchronized (mPrimaryClipChangedListeners) {
164 if (mPrimaryClipChangedListeners.size() == 0) {
165 try {
166 getService().addPrimaryClipChangedListener(
Dianne Hackborn95d78532013-09-11 09:51:14 -0700167 mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700168 } catch (RemoteException e) {
169 }
170 }
171 mPrimaryClipChangedListeners.add(what);
172 }
173 }
174
175 public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
176 synchronized (mPrimaryClipChangedListeners) {
177 mPrimaryClipChangedListeners.remove(what);
178 if (mPrimaryClipChangedListeners.size() == 0) {
179 try {
180 getService().removePrimaryClipChangedListener(
181 mPrimaryClipChangedServiceListener);
182 } catch (RemoteException e) {
183 }
184 }
185 }
186 }
187
188 /**
189 * @deprecated Use {@link #getPrimaryClip()} instead. This retrieves
190 * the primary clip and tries to coerce it to a string.
191 */
192 public CharSequence getText() {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700193 ClipData clip = getPrimaryClip();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700194 if (clip != null && clip.getItemCount() > 0) {
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800195 return clip.getItemAt(0).coerceToText(mContext);
Dianne Hackborn9f531192010-08-04 17:48:03 -0700196 }
197 return null;
198 }
199
200 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700201 * @deprecated Use {@link #setPrimaryClip(ClipData)} instead. This
Dianne Hackborn9f531192010-08-04 17:48:03 -0700202 * creates a ClippedItem holding the given text and sets it as the
203 * primary clip. It has no label or icon.
204 */
205 public void setText(CharSequence text) {
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800206 setPrimaryClip(ClipData.newPlainText(null, text));
Dianne Hackborn9f531192010-08-04 17:48:03 -0700207 }
208
209 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700210 * @deprecated Use {@link #hasPrimaryClip()} instead.
Dianne Hackborn9f531192010-08-04 17:48:03 -0700211 */
212 public boolean hasText() {
213 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700214 return getService().hasClipboardText(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700215 } catch (RemoteException e) {
216 return false;
217 }
218 }
219
220 void reportPrimaryClipChanged() {
221 Object[] listeners;
222
223 synchronized (mPrimaryClipChangedListeners) {
224 final int N = mPrimaryClipChangedListeners.size();
225 if (N <= 0) {
226 return;
227 }
228 listeners = mPrimaryClipChangedListeners.toArray();
229 }
230
231 for (int i=0; i<listeners.length; i++) {
232 ((OnPrimaryClipChangedListener)listeners[i]).onPrimaryClipChanged();
233 }
234 }
235}