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