blob: 1266f73a2f448975e15ca7126959f5bbda3c152f [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) {
Jeff Sharkey344744b2016-01-28 19:03:30 -0700121 clip.prepareToLeaveProcess(true);
Jeff Sharkeya14acd22013-04-02 18:27:45 -0700122 }
Dianne Hackborn95d78532013-09-11 09:51:14 -0700123 getService().setPrimaryClip(clip, mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700124 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700125 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700126 }
127 }
128
129 /**
130 * Returns the current primary clip on the clipboard.
131 */
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700132 public ClipData getPrimaryClip() {
Dianne Hackborn9f531192010-08-04 17:48:03 -0700133 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700134 return getService().getPrimaryClip(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700135 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700136 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700137 }
138 }
139
140 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700141 * Returns a description of the current primary clip on the clipboard
142 * but not a copy of its data.
143 */
144 public ClipDescription getPrimaryClipDescription() {
145 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700146 return getService().getPrimaryClipDescription(mContext.getOpPackageName());
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700147 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700148 throw e.rethrowFromSystemServer();
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700149 }
150 }
151
152 /**
Dianne Hackborn9f531192010-08-04 17:48:03 -0700153 * Returns true if there is currently a primary clip on the clipboard.
154 */
155 public boolean hasPrimaryClip() {
156 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700157 return getService().hasPrimaryClip(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700158 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700159 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700160 }
161 }
162
163 public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
164 synchronized (mPrimaryClipChangedListeners) {
165 if (mPrimaryClipChangedListeners.size() == 0) {
166 try {
167 getService().addPrimaryClipChangedListener(
Dianne Hackborn95d78532013-09-11 09:51:14 -0700168 mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700169 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700170 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700171 }
172 }
173 mPrimaryClipChangedListeners.add(what);
174 }
175 }
176
177 public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
178 synchronized (mPrimaryClipChangedListeners) {
179 mPrimaryClipChangedListeners.remove(what);
180 if (mPrimaryClipChangedListeners.size() == 0) {
181 try {
182 getService().removePrimaryClipChangedListener(
183 mPrimaryClipChangedServiceListener);
184 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700185 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700186 }
187 }
188 }
189 }
190
191 /**
192 * @deprecated Use {@link #getPrimaryClip()} instead. This retrieves
193 * the primary clip and tries to coerce it to a string.
194 */
195 public CharSequence getText() {
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700196 ClipData clip = getPrimaryClip();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700197 if (clip != null && clip.getItemCount() > 0) {
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800198 return clip.getItemAt(0).coerceToText(mContext);
Dianne Hackborn9f531192010-08-04 17:48:03 -0700199 }
200 return null;
201 }
202
203 /**
Dianne Hackborn1040dc42010-08-26 22:11:06 -0700204 * @deprecated Use {@link #setPrimaryClip(ClipData)} instead. This
Dianne Hackborn9f531192010-08-04 17:48:03 -0700205 * creates a ClippedItem holding the given text and sets it as the
206 * primary clip. It has no label or icon.
207 */
208 public void setText(CharSequence text) {
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800209 setPrimaryClip(ClipData.newPlainText(null, text));
Dianne Hackborn9f531192010-08-04 17:48:03 -0700210 }
211
212 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700213 * @deprecated Use {@link #hasPrimaryClip()} instead.
Dianne Hackborn9f531192010-08-04 17:48:03 -0700214 */
215 public boolean hasText() {
216 try {
Dianne Hackborn95d78532013-09-11 09:51:14 -0700217 return getService().hasClipboardText(mContext.getOpPackageName());
Dianne Hackborn9f531192010-08-04 17:48:03 -0700218 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700219 throw e.rethrowFromSystemServer();
Dianne Hackborn9f531192010-08-04 17:48:03 -0700220 }
221 }
222
223 void reportPrimaryClipChanged() {
224 Object[] listeners;
225
226 synchronized (mPrimaryClipChangedListeners) {
227 final int N = mPrimaryClipChangedListeners.size();
228 if (N <= 0) {
229 return;
230 }
231 listeners = mPrimaryClipChangedListeners.toArray();
232 }
233
234 for (int i=0; i<listeners.length; i++) {
235 ((OnPrimaryClipChangedListener)listeners[i]).onPrimaryClipChanged();
236 }
237 }
238}