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.annotation.SystemService; 20 import android.os.Handler; 21 import android.os.Message; 22 import android.os.RemoteException; 23 import android.os.ServiceManager; 24 import android.os.ServiceManager.ServiceNotFoundException; 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 * The ClipboardManager API itself is very simple: it consists of methods 34 * to atomically get and set the current primary clipboard data. That data 35 * is expressed as a {@link ClipData} object, which defines the protocol 36 * for data exchange between applications. 37 * 38 * <div class="special reference"> 39 * <h3>Developer Guides</h3> 40 * <p>For more information about using the clipboard framework, read the 41 * <a href="{@docRoot}guide/topics/clipboard/copy-paste.html">Copy and Paste</a> 42 * developer guide.</p> 43 * </div> 44 */ 45 @SystemService(Context.CLIPBOARD_SERVICE) 46 public class ClipboardManager extends android.text.ClipboardManager { 47 private final Context mContext; 48 private final IClipboard mService; 49 50 private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners 51 = new ArrayList<OnPrimaryClipChangedListener>(); 52 53 private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener 54 = new IOnPrimaryClipChangedListener.Stub() { 55 public void dispatchPrimaryClipChanged() { 56 mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED); 57 } 58 }; 59 60 static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1; 61 62 private final Handler mHandler = new Handler() { 63 @Override 64 public void handleMessage(Message msg) { 65 switch (msg.what) { 66 case MSG_REPORT_PRIMARY_CLIP_CHANGED: 67 reportPrimaryClipChanged(); 68 } 69 } 70 }; 71 72 /** 73 * Defines a listener callback that is invoked when the primary clip on the clipboard changes. 74 * Objects that want to register a listener call 75 * {@link android.content.ClipboardManager#addPrimaryClipChangedListener(OnPrimaryClipChangedListener) 76 * addPrimaryClipChangedListener()} with an 77 * object that implements OnPrimaryClipChangedListener. 78 * 79 */ 80 public interface OnPrimaryClipChangedListener { 81 82 /** 83 * Callback that is invoked by {@link android.content.ClipboardManager} when the primary 84 * clip changes. 85 */ onPrimaryClipChanged()86 void onPrimaryClipChanged(); 87 } 88 89 /** {@hide} */ ClipboardManager(Context context, Handler handler)90 public ClipboardManager(Context context, Handler handler) throws ServiceNotFoundException { 91 mContext = context; 92 mService = IClipboard.Stub.asInterface( 93 ServiceManager.getServiceOrThrow(Context.CLIPBOARD_SERVICE)); 94 } 95 96 /** 97 * Sets the current primary clip on the clipboard. This is the clip that 98 * is involved in normal cut and paste operations. 99 * 100 * @param clip The clipped data item to set. 101 */ setPrimaryClip(ClipData clip)102 public void setPrimaryClip(ClipData clip) { 103 try { 104 if (clip != null) { 105 clip.prepareToLeaveProcess(true); 106 } 107 mService.setPrimaryClip(clip, mContext.getOpPackageName()); 108 } catch (RemoteException e) { 109 throw e.rethrowFromSystemServer(); 110 } 111 } 112 113 /** 114 * Returns the current primary clip on the clipboard. 115 */ getPrimaryClip()116 public ClipData getPrimaryClip() { 117 try { 118 return mService.getPrimaryClip(mContext.getOpPackageName()); 119 } catch (RemoteException e) { 120 throw e.rethrowFromSystemServer(); 121 } 122 } 123 124 /** 125 * Returns a description of the current primary clip on the clipboard 126 * but not a copy of its data. 127 */ getPrimaryClipDescription()128 public ClipDescription getPrimaryClipDescription() { 129 try { 130 return mService.getPrimaryClipDescription(mContext.getOpPackageName()); 131 } catch (RemoteException e) { 132 throw e.rethrowFromSystemServer(); 133 } 134 } 135 136 /** 137 * Returns true if there is currently a primary clip on the clipboard. 138 */ hasPrimaryClip()139 public boolean hasPrimaryClip() { 140 try { 141 return mService.hasPrimaryClip(mContext.getOpPackageName()); 142 } catch (RemoteException e) { 143 throw e.rethrowFromSystemServer(); 144 } 145 } 146 addPrimaryClipChangedListener(OnPrimaryClipChangedListener what)147 public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) { 148 synchronized (mPrimaryClipChangedListeners) { 149 if (mPrimaryClipChangedListeners.isEmpty()) { 150 try { 151 mService.addPrimaryClipChangedListener( 152 mPrimaryClipChangedServiceListener, mContext.getOpPackageName()); 153 } catch (RemoteException e) { 154 throw e.rethrowFromSystemServer(); 155 } 156 } 157 mPrimaryClipChangedListeners.add(what); 158 } 159 } 160 removePrimaryClipChangedListener(OnPrimaryClipChangedListener what)161 public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener what) { 162 synchronized (mPrimaryClipChangedListeners) { 163 mPrimaryClipChangedListeners.remove(what); 164 if (mPrimaryClipChangedListeners.isEmpty()) { 165 try { 166 mService.removePrimaryClipChangedListener( 167 mPrimaryClipChangedServiceListener); 168 } catch (RemoteException e) { 169 throw e.rethrowFromSystemServer(); 170 } 171 } 172 } 173 } 174 175 /** 176 * @deprecated Use {@link #getPrimaryClip()} instead. This retrieves 177 * the primary clip and tries to coerce it to a string. 178 */ 179 @Deprecated getText()180 public CharSequence getText() { 181 ClipData clip = getPrimaryClip(); 182 if (clip != null && clip.getItemCount() > 0) { 183 return clip.getItemAt(0).coerceToText(mContext); 184 } 185 return null; 186 } 187 188 /** 189 * @deprecated Use {@link #setPrimaryClip(ClipData)} instead. This 190 * creates a ClippedItem holding the given text and sets it as the 191 * primary clip. It has no label or icon. 192 */ 193 @Deprecated setText(CharSequence text)194 public void setText(CharSequence text) { 195 setPrimaryClip(ClipData.newPlainText(null, text)); 196 } 197 198 /** 199 * @deprecated Use {@link #hasPrimaryClip()} instead. 200 */ 201 @Deprecated hasText()202 public boolean hasText() { 203 try { 204 return mService.hasClipboardText(mContext.getOpPackageName()); 205 } catch (RemoteException e) { 206 throw e.rethrowFromSystemServer(); 207 } 208 } 209 reportPrimaryClipChanged()210 void reportPrimaryClipChanged() { 211 Object[] listeners; 212 213 synchronized (mPrimaryClipChangedListeners) { 214 final int N = mPrimaryClipChangedListeners.size(); 215 if (N <= 0) { 216 return; 217 } 218 listeners = mPrimaryClipChangedListeners.toArray(); 219 } 220 221 for (int i=0; i<listeners.length; i++) { 222 ((OnPrimaryClipChangedListener)listeners[i]).onPrimaryClipChanged(); 223 } 224 } 225 } 226