1 /** 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 17 package android.content; 18 19 import android.content.Context; 20 import android.os.Message; 21 import android.os.RemoteException; 22 import android.os.Handler; 23 import android.os.IBinder; 24 import android.os.ServiceManager; 25 26 import 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 * 36 * <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 39 * is expressed as a {@link ClipData} object, which defines the protocol 40 * for data exchange between applications. 41 * 42 * <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 * 49 * @see android.content.Context#getSystemService 50 */ 51 public 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 79 /** 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 */ 87 public interface OnPrimaryClipChangedListener { 88 89 /** 90 * Callback that is invoked by {@link android.content.ClipboardManager} when the primary 91 * clip changes. 92 */ 93 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 */ 118 public void setPrimaryClip(ClipData clip) { 119 try { 120 if (clip != null) { 121 clip.prepareToLeaveProcess(true); 122 } 123 getService().setPrimaryClip(clip, mContext.getOpPackageName()); 124 } catch (RemoteException e) { 125 throw e.rethrowFromSystemServer(); 126 } 127 } 128 129 /** 130 * Returns the current primary clip on the clipboard. 131 */ 132 public ClipData getPrimaryClip() { 133 try { 134 return getService().getPrimaryClip(mContext.getOpPackageName()); 135 } catch (RemoteException e) { 136 throw e.rethrowFromSystemServer(); 137 } 138 } 139 140 /** 141 * 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 { 146 return getService().getPrimaryClipDescription(mContext.getOpPackageName()); 147 } catch (RemoteException e) { 148 throw e.rethrowFromSystemServer(); 149 } 150 } 151 152 /** 153 * Returns true if there is currently a primary clip on the clipboard. 154 */ 155 public boolean hasPrimaryClip() { 156 try { 157 return getService().hasPrimaryClip(mContext.getOpPackageName()); 158 } catch (RemoteException e) { 159 throw e.rethrowFromSystemServer(); 160 } 161 } 162 163 public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) { 164 synchronized (mPrimaryClipChangedListeners) { 165 if (mPrimaryClipChangedListeners.size() == 0) { 166 try { 167 getService().addPrimaryClipChangedListener( 168 mPrimaryClipChangedServiceListener, mContext.getOpPackageName()); 169 } catch (RemoteException e) { 170 throw e.rethrowFromSystemServer(); 171 } 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) { 185 throw e.rethrowFromSystemServer(); 186 } 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() { 196 ClipData clip = getPrimaryClip(); 197 if (clip != null && clip.getItemCount() > 0) { 198 return clip.getItemAt(0).coerceToText(mContext); 199 } 200 return null; 201 } 202 203 /** 204 * @deprecated Use {@link #setPrimaryClip(ClipData)} instead. This 205 * 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) { 209 setPrimaryClip(ClipData.newPlainText(null, text)); 210 } 211 212 /** 213 * @deprecated Use {@link #hasPrimaryClip()} instead. 214 */ 215 public boolean hasText() { 216 try { 217 return getService().hasClipboardText(mContext.getOpPackageName()); 218 } catch (RemoteException e) { 219 throw e.rethrowFromSystemServer(); 220 } 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 } 239