├── .gitignore ├── .idea ├── assetWizardSettings.xml ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── dictionaries │ └── congs.xml ├── gradle.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── app-release.apk │ └── output.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── csw │ │ └── xposedclipboard │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── xposed_init │ ├── ic_launcher-web.png │ ├── java │ │ └── com │ │ │ └── csw │ │ │ └── xposedclipboard │ │ │ ├── BaseRecyclerViewAdapter.java │ │ │ ├── ClipBean.java │ │ │ ├── DataBindingAdapter.java │ │ │ ├── DrawerAdapter.java │ │ │ ├── DrawerBean.java │ │ │ ├── MainActivity.java │ │ │ ├── MyItemTouchHelperCallback.java │ │ │ ├── Xposed.java │ │ │ └── util │ │ │ ├── MyTimeUtil.java │ │ │ └── MyToast.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── drawer_github_icon.png │ │ ├── drawer_record_icon.png │ │ ├── drawer_toast_icon.png │ │ ├── ic_launcher_background.xml │ │ ├── menu_popup_icon.png │ │ └── toast_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── clip_item.xml │ │ ├── drawer_item.xml │ │ ├── drawer_layout.xml │ │ └── toast_layout.xml │ │ ├── menu │ │ ├── menu_copy.xml │ │ └── menu_toolbar.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── csw │ └── xposedclipboard │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/assetWizardSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 56 | 57 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/dictionaries/congs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | xposed 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xposed_Clipboard 2 | 检测手机剪切板的使用 3 | 通过hook ClipboardManager类的setPrimaryClip(clipData)方法,达到监视剪切板的效果。 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | buildToolsVersion '27.0.3' 6 | 7 | defaultConfig { 8 | applicationId "com.csw.xposedclipboard" 9 | minSdkVersion 21 10 | targetSdkVersion 27 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } } 22 | dataBinding { 23 | enabled = true 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(include: ['*.jar'], dir: 'libs') 29 | implementation 'com.android.support:appcompat-v7:27.1.1' 30 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 31 | testImplementation 'junit:junit:4.12' 32 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 34 | 35 | compileOnly 'de.robv.android.xposed:api:82' 36 | compileOnly 'de.robv.android.xposed:api:82:sources' 37 | implementation 'com.android.support:design:27.1.1' 38 | implementation 'com.android.support:cardview-v7:27.1.1' 39 | } 40 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/androidTest/java/com/csw/xposedclipboard/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.csw.xposedclipboard", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | com.csw.xposedclipboard.Xposed -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/BaseRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.content.Context; 4 | import android.databinding.DataBindingUtil; 5 | import android.databinding.ViewDataBinding; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by 丛 on 2018/5/28 0028. 16 | */ 17 | public class BaseRecyclerViewAdapter extends RecyclerView.Adapter { 18 | private final LayoutInflater inflate; 19 | private ArrayList beanList; 20 | private int BRId; 21 | private int layoutId; 22 | 23 | /** 24 | * 多布局构造方法,当有多个布局时,重写onCreateViewHolder()方法,在里面指定布局 25 | * @param context 用来会的布局加载器 26 | */ 27 | public BaseRecyclerViewAdapter(Context context) { 28 | inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 29 | beanList = new ArrayList<>(); 30 | this.BRId = -1; 31 | } 32 | 33 | /** 34 | * 单布局使用此构造方法,在构造方法中就指定布局文件 35 | * @param context 36 | * @param BRId bean类 37 | * @param layoutId item布局资源 38 | */ 39 | public BaseRecyclerViewAdapter(Context context, int BRId, int layoutId) { 40 | inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 41 | beanList = new ArrayList<>(); 42 | this.BRId = BRId; 43 | this.layoutId = layoutId; 44 | } 45 | 46 | /** 47 | * 多布局需要重写此方法 48 | * @param parent 49 | * @param viewType 50 | * @return 51 | */ 52 | @NonNull 53 | @Override 54 | public BindingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 55 | // 绑定试图 56 | ViewDataBinding binding = DataBindingUtil.inflate(inflate, layoutId, parent, false); 57 | return new BindingViewHolder(binding); 58 | } 59 | 60 | /** 61 | * 多布局需要完全重写此方法 62 | * 单布局无需重写此方法,如果要重写,可以保留“数据填充”代码部分 63 | * 多布局BRId为-1,单布局存在正常BRId 64 | * @param holder 65 | * @param position 66 | */ 67 | @Override 68 | public void onBindViewHolder(@NonNull final BaseRecyclerViewAdapter.BindingViewHolder holder, 69 | final int position) { 70 | // 数据填充代码 71 | if (BRId != -1) { 72 | final B bean = beanList.get(position); 73 | holder.binding.setVariable(BRId, bean); 74 | holder.binding.executePendingBindings(); 75 | holder.itemView.setOnClickListener(new View.OnClickListener() { 76 | @Override 77 | public void onClick(View v) { 78 | if (itemClickListener != null) 79 | itemClickListener.onItemClick(holder.getAdapterPosition()); 80 | } 81 | }); 82 | holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 83 | @Override 84 | public boolean onLongClick(View v) { 85 | if (itemClickListener != null) 86 | itemClickListener.onItemLongClick(holder.getAdapterPosition()); 87 | return false; 88 | } 89 | }); 90 | } 91 | } 92 | 93 | @Override 94 | public int getItemCount() { 95 | return beanList.size(); 96 | } 97 | 98 | // 默认从尾部添加,不需要更新位置 99 | public void add(int pos, B bean) { 100 | beanList.add(pos, bean); 101 | notifyItemInserted(pos); 102 | } 103 | 104 | /**从0号位置添加数据,更新位置 105 | * @param bean 106 | */ 107 | public void addStart(B bean) { 108 | beanList.add(0 ,bean); 109 | notifyItemInserted(0); 110 | } 111 | 112 | // 从尾部添加,不需要更新位置 113 | public void addEnd(B bean) { 114 | beanList.add(bean); 115 | notifyItemInserted(beanList.size() - 1); 116 | } 117 | 118 | public void addAll(int pos, ArrayList beanList) { 119 | this.beanList.addAll(pos, beanList); 120 | notifyDataSetChanged(); 121 | } 122 | 123 | /** 124 | * 从0号位置添加数据 125 | * @param beanList 126 | */ 127 | public void addAllStart(ArrayList beanList) { 128 | this.beanList.addAll(0, beanList); 129 | notifyDataSetChanged(); 130 | } 131 | 132 | public void addAllEnd(ArrayList beanList) { 133 | this.beanList.addAll(beanList); 134 | notifyDataSetChanged(); 135 | } 136 | 137 | public void remove(int position) { 138 | try { // 滑动删除可能报错 139 | if (beanList.size() == 0) // 防止数组越界异常 140 | return; 141 | beanList.remove(position); 142 | notifyItemRemoved(position); 143 | } catch (Exception e) { 144 | e.printStackTrace(); 145 | } 146 | if (itemClickListener != null) 147 | itemClickListener.onItemRemove(); 148 | } 149 | 150 | public void removeAll() { 151 | beanList.clear(); 152 | notifyDataSetChanged(); 153 | } 154 | 155 | public void set(int position, B bean) { 156 | this.beanList.set(position, bean); 157 | notifyItemChanged(position); 158 | } 159 | 160 | public ArrayList getBeanList() { 161 | return this.beanList; 162 | } 163 | 164 | protected void setBeanList(ArrayList beanList) { 165 | this.beanList = beanList; 166 | } 167 | 168 | protected LayoutInflater getInflate() { 169 | return this.inflate; 170 | } 171 | 172 | private ItemClickListener itemClickListener; 173 | 174 | public void setItemClickListener(ItemClickListener listener) { 175 | this.itemClickListener = listener; 176 | } 177 | 178 | public interface ItemClickListener { 179 | void onItemClick(int pos); 180 | void onItemLongClick(int pos); 181 | void onItemRemove(); 182 | } 183 | 184 | static class BindingViewHolder extends RecyclerView.ViewHolder { 185 | private ViewDataBinding binding; 186 | 187 | BindingViewHolder(ViewDataBinding binding) { 188 | super(binding.getRoot()); 189 | this.binding = binding; 190 | } 191 | 192 | public ViewDataBinding getBinding() { 193 | return binding; 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/ClipBean.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.databinding.BaseObservable; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * Created by 丛 on 2018/5/28 0028. 9 | */ 10 | public class ClipBean extends BaseObservable implements Serializable { 11 | private byte[] icon; // 二进制应用图标 12 | private String name; // 应用名 13 | private String timeStamp; // 时间戳 14 | private String time; // 格式化后的时间(如:昨天5:05) 15 | private String clipText; // 剪切数据 16 | private String extra; // json格式 17 | 18 | public byte[] getIcon() { 19 | return this.icon; 20 | } 21 | 22 | public void setIcon(byte[] icon) { 23 | this.icon = icon; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public String getTimeStamp() { 35 | return timeStamp; 36 | } 37 | 38 | public void setTimeStamp(String timeStamp) { 39 | this.timeStamp = timeStamp; 40 | } 41 | 42 | public String getTime() { 43 | return time; 44 | } 45 | 46 | public void setTime(String time) { 47 | this.time = time; 48 | } 49 | 50 | public String getClipText() { 51 | return clipText; 52 | } 53 | 54 | public void setClipText(String clipText) { 55 | this.clipText = clipText; 56 | } 57 | 58 | public String getExtra() { 59 | return extra; 60 | } 61 | 62 | public void setExtra(String extra) { 63 | this.extra = extra; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/DataBindingAdapter.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.databinding.BindingAdapter; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.widget.ImageView; 9 | 10 | /** 11 | * Created by 丛 on 2018/5/31 0031. 12 | */ 13 | public class DataBindingAdapter { 14 | 15 | @BindingAdapter("srcBytes") 16 | public static void setIcon(ImageView imageView, byte[] icon) { 17 | Drawable d = new BitmapDrawable(MainActivity.weakReference.get().getResources(), 18 | getBitmap(icon)); 19 | imageView.setImageDrawable(d); 20 | } 21 | 22 | private static Bitmap getBitmap(byte[] data){ 23 | return BitmapFactory.decodeByteArray(data, 0, data.length);//从字节数组解码位图 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/DrawerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | 7 | import com.csw.xposedclipboard.databinding.DrawerItemBinding; 8 | 9 | /** 10 | * Created by 丛 on 2018/5/29 0029. 11 | */ 12 | public class DrawerAdapter extends BaseRecyclerViewAdapter { 13 | 14 | public DrawerAdapter(Context context, int BRId, int layoutId) { 15 | super(context, BRId, layoutId); 16 | } 17 | 18 | @Override 19 | public void onBindViewHolder(@NonNull final BindingViewHolder holder, int position) { 20 | super.onBindViewHolder(holder, position); 21 | final DrawerItemBinding binding = (DrawerItemBinding) holder.getBinding(); 22 | binding.switchSetting.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | if (listener != null) { 26 | int pos = holder.getAdapterPosition(); 27 | boolean isChecked = binding.switchSetting.isChecked(); 28 | listener.onSwitchClickListener(getBeanList().get(pos), pos, isChecked); 29 | } 30 | } 31 | }); 32 | } 33 | 34 | private DrawerClickListener listener; 35 | 36 | public void setListener(DrawerClickListener listener) { 37 | this.listener = listener; 38 | } 39 | 40 | public interface DrawerClickListener { 41 | void onSwitchClickListener(DrawerBean bean, int pos, boolean isChecked); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/DrawerBean.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.databinding.BaseObservable; 4 | import android.databinding.Bindable; 5 | import android.graphics.drawable.Drawable; 6 | 7 | /** 8 | * Created by 丛 on 2018/5/29 0029. 9 | */ 10 | public class DrawerBean extends BaseObservable { 11 | private String name; 12 | private Drawable icon; 13 | private boolean isNeedSwitch; 14 | private boolean isSwitchChecked; 15 | 16 | public DrawerBean() { 17 | isNeedSwitch = false; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public Drawable getIcon() { 29 | return icon; 30 | } 31 | 32 | public void setIcon(Drawable icon) { 33 | this.icon = icon; 34 | } 35 | 36 | public boolean getIsNeedSwitch() { 37 | return isNeedSwitch; 38 | } 39 | 40 | public void setIsNeedSwitch(boolean isNeedSwitch) { 41 | this.isNeedSwitch = isNeedSwitch; 42 | } 43 | 44 | @Bindable 45 | public boolean getIsSwitchChecked() { 46 | return isSwitchChecked; 47 | } 48 | 49 | public void setIsSwitchChecked(boolean isSwitchChecked) { 50 | this.isSwitchChecked = isSwitchChecked; 51 | notifyPropertyChanged(BR.isSwitchChecked); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.content.ClipData; 4 | import android.content.ClipboardManager; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.databinding.DataBindingUtil; 8 | import android.net.Uri; 9 | import android.support.v7.app.ActionBarDrawerToggle; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.os.Bundle; 12 | import android.support.v7.widget.LinearLayoutManager; 13 | import android.support.v7.widget.PopupMenu; 14 | import android.support.v7.widget.RecyclerView; 15 | import android.support.v7.widget.helper.ItemTouchHelper; 16 | import android.util.Log; 17 | import android.view.Gravity; 18 | import android.view.KeyEvent; 19 | import android.view.MenuInflater; 20 | import android.view.MenuItem; 21 | import android.view.View; 22 | 23 | import com.csw.xposedclipboard.databinding.ActivityMainBinding; 24 | import com.csw.xposedclipboard.util.MyTimeUtil; 25 | import com.csw.xposedclipboard.util.MyToast; 26 | 27 | import java.io.File; 28 | import java.io.FileInputStream; 29 | import java.io.FileOutputStream; 30 | import java.io.ObjectInputStream; 31 | import java.io.ObjectOutputStream; 32 | import java.lang.ref.WeakReference; 33 | import java.util.ArrayList; 34 | import java.util.HashMap; 35 | 36 | public class MainActivity extends AppCompatActivity { 37 | public static WeakReference weakReference; 38 | 39 | private final String dataPath = 40 | "sdcard" + File.separator + "Android" + File.separator + "data" + File.separator 41 | + "com.csw.xposedclipboard" + File.separator + "clipboard_data.dat"; 42 | 43 | private final String settingPath = 44 | "sdcard" + File.separator + "Android" + File.separator + "data" + File.separator 45 | + "com.csw.xposedclipboard" + File.separator + "setting.dat"; 46 | 47 | 48 | private ActivityMainBinding binding; 49 | private BaseRecyclerViewAdapter adapter; 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | binding = 55 | DataBindingUtil.setContentView(this, R.layout.activity_main); 56 | 57 | weakReference = new WeakReference<>(this); 58 | ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, 59 | binding.drawerLayout, binding.toolBar, R.string.open, R.string.close); 60 | drawerToggle.syncState(); 61 | initDrawer(); 62 | initRecyclerView(); 63 | } 64 | 65 | @Override 66 | protected void onStart() { 67 | super.onStart(); 68 | ArrayList clipBeanList = getLocalClipData(); 69 | if (clipBeanList != null) 70 | refreshClipBean(clipBeanList); 71 | } 72 | 73 | @Override 74 | public boolean onKeyDown(int keyCode, KeyEvent event) { 75 | if (keyCode == KeyEvent.KEYCODE_BACK) { 76 | if (binding.drawerLayout.isDrawerOpen(Gravity.START)) { 77 | binding.drawerLayout.closeDrawer(Gravity.START); 78 | return true; 79 | } 80 | } 81 | return super.onKeyDown(keyCode, event); 82 | } 83 | 84 | private void initDrawer() { 85 | RecyclerView recyclerView = binding.include.recyclerViewDrawer; 86 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 87 | DrawerAdapter adapter = 88 | new DrawerAdapter(this, BR.DrawerBean, R.layout.drawer_item); 89 | adapter.setListener(new DrawerAdapter.DrawerClickListener() { 90 | @Override 91 | public void onSwitchClickListener(DrawerBean bean, int pos, boolean isChecked) { 92 | bean.setIsSwitchChecked(isChecked); 93 | HashMap settingMap = readConfig(); 94 | if (pos == 0) { 95 | settingMap.put("isRecord", String.valueOf(isChecked)); 96 | } else if (pos == 1) { 97 | settingMap.put("isToast", String.valueOf(isChecked)); 98 | if (isChecked) { 99 | MyToast.show(MainActivity.this, null, "Toast提示开启"); 100 | } 101 | } 102 | writeConfig(settingMap); 103 | } 104 | }); 105 | adapter.setItemClickListener(new BaseRecyclerViewAdapter.ItemClickListener() { 106 | @Override 107 | public void onItemClick(int pos) { 108 | if (pos == 2) { 109 | Uri uri = Uri.parse("https://github.com/congshengwu/Xposed_Clipboard"); 110 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 111 | startActivity(intent); 112 | } 113 | } 114 | 115 | @Override 116 | public void onItemLongClick(int pos) { 117 | 118 | } 119 | 120 | @Override 121 | public void onItemRemove() { 122 | 123 | } 124 | }); 125 | recyclerView.setAdapter(adapter); 126 | HashMap settingMap = readConfig(); 127 | DrawerBean bean1 = new DrawerBean(); 128 | bean1.setName("记录剪切板使用数据"); 129 | bean1.setIsNeedSwitch(true); 130 | bean1.setIsSwitchChecked(Boolean.valueOf(settingMap.get("isRecord"))); 131 | bean1.setIcon(getDrawable(R.drawable.drawer_record_icon)); 132 | DrawerBean bean2 = new DrawerBean(); 133 | bean2.setName("剪切板使用时底部Toast提示"); 134 | bean2.setIsNeedSwitch(true); 135 | bean2.setIsSwitchChecked(Boolean.valueOf(settingMap.get("isToast"))); 136 | bean2.setIcon(getDrawable(R.drawable.drawer_toast_icon)); 137 | DrawerBean bean3 = new DrawerBean(); 138 | bean3.setName("GitHub开源地址"); 139 | bean3.setIsNeedSwitch(false); 140 | bean3.setIcon(getDrawable(R.drawable.drawer_github_icon)); 141 | adapter.addEnd(bean1); 142 | adapter.addEnd(bean2); 143 | adapter.addEnd(bean3); 144 | } 145 | 146 | private ArrayList getLocalClipData() { 147 | try { 148 | File file = new File(dataPath); 149 | if (!file.exists()) { 150 | return null; 151 | } 152 | FileInputStream fileInput = new FileInputStream(dataPath); 153 | ObjectInputStream objInput = new ObjectInputStream(fileInput); 154 | Object object = objInput.readObject(); 155 | if (object == null) { 156 | binding.textViewNothing.setVisibility(View.VISIBLE); 157 | return null; 158 | } else { 159 | ArrayList clipBeanList = (ArrayList) object; 160 | if (clipBeanList.size() == 0) 161 | binding.textViewNothing.setVisibility(View.VISIBLE); 162 | else 163 | binding.textViewNothing.setVisibility(View.GONE); 164 | return clipBeanList; 165 | } 166 | } catch (Exception e) { 167 | e.printStackTrace(); 168 | binding.textViewNothing.setVisibility(View.VISIBLE); 169 | } 170 | return null; 171 | } 172 | 173 | private void initRecyclerView() { 174 | binding.recyclerViewMain.setLayoutManager(new LinearLayoutManager(this)); 175 | adapter = new BaseRecyclerViewAdapter<>( 176 | this, BR.ClipBean, R.layout.clip_item); 177 | adapter.setItemClickListener(new BaseRecyclerViewAdapter.ItemClickListener() { 178 | @Override 179 | public void onItemClick(int pos) { 180 | 181 | } 182 | 183 | @Override 184 | public void onItemLongClick(final int pos) { 185 | View view = binding.recyclerViewMain.getChildAt(pos); 186 | //创建弹出式菜单对象(最低版本11) 187 | PopupMenu popup = new PopupMenu(MainActivity.this, view);//第二个参数是绑定的那个view 188 | //获取菜单填充器 189 | MenuInflater inflater = popup.getMenuInflater(); 190 | //填充菜单 191 | inflater.inflate(R.menu.menu_copy, popup.getMenu()); 192 | //绑定菜单项的点击事件 193 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 194 | @Override 195 | public boolean onMenuItemClick(MenuItem item) { 196 | if (item.getItemId() == R.id.menu_copy) { 197 | ClipboardManager cm = (ClipboardManager) MainActivity.this.getSystemService( 198 | Context.CLIPBOARD_SERVICE); 199 | if (cm != null) { 200 | String clipStr = adapter.getBeanList().get(pos).getClipText(); 201 | cm.setPrimaryClip(ClipData.newPlainText("text", clipStr)); 202 | } 203 | } 204 | return false; 205 | } 206 | }); 207 | popup.show(); 208 | } 209 | 210 | @Override 211 | public void onItemRemove() { 212 | if (adapter.getBeanList().size() == 0) 213 | binding.textViewNothing.setVisibility(View.VISIBLE); 214 | saveClipData(adapter.getBeanList()); 215 | } 216 | }); 217 | binding.recyclerViewMain.setAdapter(adapter); 218 | // 侧滑删除 219 | MyItemTouchHelperCallback callback = new MyItemTouchHelperCallback(adapter); 220 | ItemTouchHelper helper = new ItemTouchHelper(callback); 221 | helper.attachToRecyclerView(binding.recyclerViewMain); 222 | } 223 | 224 | private void refreshClipBean(ArrayList beanList) { 225 | adapter.removeAll(); 226 | for (ClipBean bean: beanList) { 227 | bean.setTime(MyTimeUtil.formatTime(bean.getTimeStamp())); 228 | adapter.addEnd(bean); 229 | } 230 | } 231 | 232 | public void onClick(View view) { 233 | int id = view.getId(); 234 | if (id == R.id.imageView_menu) { 235 | //创建弹出式菜单对象 236 | PopupMenu popup = new PopupMenu(this, view);//第二个参数是绑定的那个view 237 | //获取菜单填充器 238 | MenuInflater inflater = popup.getMenuInflater(); 239 | //填充菜单 240 | inflater.inflate(R.menu.menu_toolbar, popup.getMenu()); 241 | //绑定菜单项的点击事件 242 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 243 | @Override 244 | public boolean onMenuItemClick(MenuItem item) { 245 | if (item.getItemId() == R.id.menu_clearData) { 246 | clearAllLocalClipData(); 247 | } 248 | return false; 249 | } 250 | }); 251 | //显示(这一行代码不要忘记了) 252 | popup.show(); 253 | } 254 | } 255 | 256 | private void clearAllLocalClipData() { 257 | File file = new File(dataPath); 258 | if (file.exists()) 259 | file.delete(); 260 | if (adapter != null) { 261 | adapter.removeAll(); 262 | binding.textViewNothing.setVisibility(View.VISIBLE); 263 | } 264 | } 265 | 266 | private void saveClipData(ArrayList beanList) { 267 | try { 268 | File file = new File(dataPath); 269 | if (!file.exists()) { 270 | file.getParentFile().mkdirs(); 271 | file.createNewFile(); 272 | } 273 | // 存到本地 274 | FileOutputStream fileOut = new FileOutputStream(file); 275 | ObjectOutputStream objOut = new ObjectOutputStream(fileOut); 276 | objOut.writeObject(beanList); 277 | objOut.flush(); 278 | objOut.close(); 279 | fileOut.close(); 280 | } catch (Exception e) { 281 | e.printStackTrace(); 282 | } 283 | } 284 | 285 | private void writeConfig(HashMap settingMap) { 286 | try { 287 | File file = new File(settingPath); 288 | if (!file.exists()) { 289 | file.getParentFile().mkdirs(); 290 | file.createNewFile(); 291 | } 292 | FileOutputStream fileOutput = new FileOutputStream(file); 293 | ObjectOutputStream objOutput = new ObjectOutputStream(fileOutput); 294 | objOutput.writeObject(settingMap); 295 | objOutput.flush(); 296 | objOutput.close(); 297 | fileOutput.close(); 298 | } catch (Exception e) { 299 | e.printStackTrace(); 300 | } 301 | } 302 | 303 | /** 304 | * 读取本地存储的配置类,如果没有该文件类,则生成默认配置类,并将该类存到本地. 305 | * @return 306 | */ 307 | private HashMap readConfig() { 308 | try { 309 | File file = new File(settingPath); 310 | if (!file.exists()) { 311 | HashMap settingMap = new HashMap<>(); 312 | settingMap.put("isRecord", String.valueOf(true)); 313 | settingMap.put("isToast", String.valueOf(true)); 314 | writeConfig(settingMap); 315 | return settingMap; 316 | } 317 | FileInputStream fileInput = new FileInputStream(file); 318 | ObjectInputStream objInput = new ObjectInputStream(fileInput); 319 | Object object = objInput.readObject(); 320 | objInput.close(); 321 | fileInput.close(); 322 | if (object == null) { 323 | HashMap settingMap = new HashMap<>(); 324 | settingMap.put("isRecord", String.valueOf(true)); 325 | settingMap.put("isToast", String.valueOf(true)); 326 | return settingMap; 327 | } else { 328 | return (HashMap) object; 329 | } 330 | } catch (Exception e) { 331 | e.printStackTrace(); 332 | } 333 | HashMap settingMap = new HashMap<>(); 334 | settingMap.put("isRecord", String.valueOf(true)); 335 | settingMap.put("isToast", String.valueOf(true)); 336 | return settingMap; 337 | } 338 | 339 | } 340 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/MyItemTouchHelperCallback.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.support.v7.widget.helper.ItemTouchHelper; 5 | 6 | /** 7 | * Created by 丛 on 2018/5/31 0031. 8 | */ 9 | public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback { 10 | private BaseRecyclerViewAdapter adapter; 11 | 12 | MyItemTouchHelperCallback(BaseRecyclerViewAdapter adapter) { 13 | this.adapter = adapter; 14 | } 15 | 16 | @Override 17 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 18 | int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; //只允许从右向左侧滑 19 | return makeMovementFlags(0, swipeFlags); 20 | } 21 | 22 | @Override 23 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 24 | return false; 25 | } 26 | 27 | @Override 28 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 29 | adapter.remove(viewHolder.getAdapterPosition()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/Xposed.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import android.app.AndroidAppHelper; 4 | import android.content.ClipData; 5 | import android.content.ClipboardManager; 6 | import android.content.Context; 7 | import android.content.pm.PackageManager; 8 | import android.graphics.Bitmap; 9 | import android.graphics.Canvas; 10 | import android.graphics.PixelFormat; 11 | import android.graphics.drawable.Drawable; 12 | import android.os.Environment; 13 | 14 | import com.csw.xposedclipboard.util.MyToast; 15 | 16 | import java.io.ByteArrayOutputStream; 17 | import java.io.File; 18 | import java.io.FileInputStream; 19 | import java.io.FileOutputStream; 20 | import java.io.ObjectInputStream; 21 | import java.io.ObjectOutputStream; 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | 25 | import de.robv.android.xposed.IXposedHookLoadPackage; 26 | import de.robv.android.xposed.XC_MethodHook; 27 | import de.robv.android.xposed.XposedBridge; 28 | import de.robv.android.xposed.XposedHelpers; 29 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 30 | 31 | /** 32 | * Created by 丛 on 2018/5/22 0022. 33 | */ 34 | public class Xposed implements IXposedHookLoadPackage { 35 | private final String TAG = "剪切板探测器:"; 36 | 37 | @Override 38 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 39 | 40 | XposedHelpers.findAndHookMethod(ClipboardManager.class, "setPrimaryClip", 41 | ClipData.class, new XC_MethodHook() { 42 | @Override 43 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 44 | super.beforeHookedMethod(param); 45 | XposedBridge.log(TAG + "hook成功"); 46 | } 47 | 48 | @Override 49 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 50 | super.afterHookedMethod(param); 51 | // 获取剪切板内容 52 | ClipData clipData = (ClipData) param.args[0]; 53 | String clipStr = clipData.getItemAt(0).getText().toString(); 54 | // 得到应用上下文 55 | Context curContext = 56 | AndroidAppHelper.currentApplication().getApplicationContext(); 57 | PackageManager pm = curContext.getPackageManager(); 58 | // 获取应用名 59 | String appName = lpparam.appInfo.loadLabel(pm).toString(); 60 | // 获取应用图标 61 | Drawable icon = lpparam.appInfo.loadIcon(pm); 62 | // 准备剪切板内容 63 | String showText = "\"" + appName + "\"" + "使用了剪切板。内容为:" + clipStr; 64 | // Xposed打印log信息 65 | XposedBridge.log(TAG + showText); 66 | 67 | HashMap settingMap = readConfig(); 68 | 69 | // toast提示 70 | if (Boolean.valueOf(settingMap.get("isToast"))) 71 | MyToast.show(curContext, icon, showText); 72 | // 将剪切板内容保存到本地 73 | if (Boolean.valueOf(settingMap.get("isRecord"))) 74 | saveDataToLocal(appName, clipStr, icon); 75 | } 76 | }); 77 | } 78 | 79 | private void saveDataToLocal(String appName, String clipStr, Drawable icon) { 80 | try { 81 | String dataPath = 82 | Environment.getExternalStorageDirectory().getAbsolutePath() + 83 | File.separator + "Android" + File.separator + "data" 84 | + File.separator + "com.csw.xposedclipboard"; 85 | ArrayList clipBeanList; 86 | File file = new File(dataPath, "clipboard_data.dat"); 87 | if (!file.getParentFile().exists()) { // 文件不存在 88 | file.getParentFile().mkdirs(); 89 | boolean state = file.createNewFile(); 90 | if (!state) // 文件创建失败 91 | return; 92 | else //文件创建成功 93 | clipBeanList = new ArrayList<>(100); 94 | } else { // 文件存在 95 | // 读取本地存储的类 96 | try { 97 | FileInputStream fileInput = new FileInputStream(file); 98 | ObjectInputStream objInput = new ObjectInputStream(fileInput); 99 | Object object = objInput.readObject(); 100 | if (object == null) 101 | clipBeanList = new ArrayList<>(100); 102 | else 103 | clipBeanList = (ArrayList) object; 104 | objInput.close(); 105 | fileInput.close(); 106 | } catch (Exception e) { // 读取本地文件失败 107 | e.printStackTrace(); 108 | clipBeanList = new ArrayList<>(100); 109 | } 110 | } 111 | // 构建一条剪切数据 112 | ClipBean bean = new ClipBean(); 113 | bean.setName(appName); 114 | bean.setTimeStamp(System.currentTimeMillis() + ""); 115 | bean.setTime(System.currentTimeMillis() + ""); 116 | bean.setClipText(clipStr); 117 | bean.setIcon(getBytes(icon)); 118 | bean.setExtra("{}"); 119 | 120 | if (clipBeanList.size() < 100) { 121 | clipBeanList.add(0, bean); 122 | } else { 123 | clipBeanList.remove(clipBeanList.size() - 1); 124 | clipBeanList.add(0, bean); 125 | } 126 | // 存到本地 127 | FileOutputStream fileOut = new FileOutputStream(file); 128 | ObjectOutputStream objOut = new ObjectOutputStream(fileOut); 129 | objOut.writeObject(clipBeanList); 130 | objOut.flush(); 131 | objOut.close(); 132 | fileOut.close(); 133 | } catch (Exception e) { 134 | e.printStackTrace(); 135 | } 136 | } 137 | 138 | private byte[] getBytes(Drawable icon) { 139 | Bitmap bitmap = drawableToBitmap(icon); 140 | //实例化字节数组输出流 141 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 142 | bitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);//压缩位图 143 | return baos.toByteArray();//创建分配字节数组 144 | } 145 | 146 | private Bitmap drawableToBitmap(Drawable drawable) { 147 | 148 | int w = drawable.getIntrinsicWidth(); 149 | int h = drawable.getIntrinsicHeight(); 150 | Bitmap.Config config = 151 | drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 152 | : Bitmap.Config.RGB_565; 153 | Bitmap bitmap = Bitmap.createBitmap(w, h, config); 154 | //注意,下面三行代码要用到,否则在View或者SurfaceView里的canvas.drawBitmap会看不到图 155 | Canvas canvas = new Canvas(bitmap); 156 | drawable.setBounds(0, 0, w, h); 157 | drawable.draw(canvas); 158 | 159 | return bitmap; 160 | } 161 | 162 | private HashMap readConfig() { 163 | try { 164 | String settingPath = 165 | Environment.getExternalStorageDirectory().getAbsolutePath() + 166 | File.separator + "Android" + File.separator + "data" 167 | + File.separator + "com.csw.xposedclipboard"; 168 | File file = new File(settingPath, "setting.dat"); 169 | if (!file.exists()) { 170 | HashMap settingMap = new HashMap<>(); 171 | settingMap.put("isRecord", String.valueOf(true)); 172 | settingMap.put("isToast", String.valueOf(true)); 173 | return settingMap; 174 | } 175 | FileInputStream fileInput = new FileInputStream(file); 176 | ObjectInputStream objInput = new ObjectInputStream(fileInput); 177 | Object object = objInput.readObject(); 178 | objInput.close(); 179 | fileInput.close(); 180 | if (object == null) { 181 | HashMap settingMap = new HashMap<>(); 182 | settingMap.put("isRecord", String.valueOf(true)); 183 | settingMap.put("isToast", String.valueOf(true)); 184 | return settingMap; 185 | } else { 186 | return (HashMap) object; 187 | } 188 | } catch (Exception e) { 189 | e.printStackTrace(); 190 | } 191 | HashMap settingMap = new HashMap<>(); 192 | settingMap.put("isRecord", String.valueOf(true)); 193 | settingMap.put("isToast", String.valueOf(true)); 194 | return settingMap; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/util/MyTimeUtil.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard.util; 2 | 3 | import java.util.Calendar; 4 | 5 | /** 6 | * Created by 丛 on 2018/5/31 0031. 7 | */ 8 | public class MyTimeUtil { 9 | 10 | public static String formatTime(String timeStr) { 11 | long timestamp = Long.valueOf(timeStr); 12 | Calendar time = Calendar.getInstance(); 13 | time.setTimeInMillis(timestamp); 14 | Calendar now = Calendar.getInstance(); 15 | if (time.get(Calendar.YEAR) == now.get(Calendar.YEAR) && 16 | time.get(Calendar.MONTH) == now.get(Calendar.MONTH) && 17 | time.get(Calendar.DAY_OF_MONTH) == now.get(Calendar.DAY_OF_MONTH)) { // 今天 18 | int deltaHour = now.get(Calendar.HOUR_OF_DAY) - time.get(Calendar.HOUR_OF_DAY); 19 | int deltaMinute = now.get(Calendar.MINUTE) - time.get(Calendar.MINUTE); 20 | int deltaTime = deltaHour * 60 + deltaMinute; 21 | // 一小时内 22 | if (deltaTime < 60) { 23 | return deltaTime == 0 ? "1" + "分钟前" : deltaTime + "分钟前"; 24 | } 25 | // 一小时外 26 | else { 27 | int hour = time.get(Calendar.HOUR_OF_DAY); 28 | int minute = time.get(Calendar.MINUTE); 29 | return (hour < 10 ? "0" + hour : "" + hour) 30 | + ":" + 31 | (minute < 10 ? "0" + minute : "" + minute); 32 | } 33 | } else if (time.get(Calendar.YEAR) == now.get(Calendar.YEAR) && 34 | time.get(Calendar.MONTH) == now.get(Calendar.MONTH) && 35 | time.get(Calendar.DAY_OF_MONTH) + 1 == now.get(Calendar.DAY_OF_MONTH)) { // 昨天 36 | int hour = time.get(Calendar.HOUR_OF_DAY); 37 | int minute = time.get(Calendar.MINUTE); 38 | return "昨天" + 39 | (hour < 10 ? "0" + hour : "" + hour) 40 | + ":" + 41 | (minute < 10 ? "0" + minute : "" + minute); 42 | } else if (time.get(Calendar.YEAR) == now.get(Calendar.YEAR)) { // 昨天之前并且是今年 43 | int hour = time.get(Calendar.HOUR_OF_DAY); 44 | int minute = time.get(Calendar.MINUTE); 45 | return (time.get(Calendar.MONTH) + 1) + "月" + time.get(Calendar.DAY_OF_MONTH) + "日" + 46 | (hour < 10 ? "0" + hour : "" + hour) 47 | + ":" + 48 | (minute < 10 ? "0" + minute : "" + minute); 49 | } else if (time.get(Calendar.YEAR) != now.get(Calendar.YEAR)) { 50 | int year = time.get(Calendar.YEAR) - 2000; 51 | int hour = time.get(Calendar.HOUR_OF_DAY); 52 | int minute = time.get(Calendar.MINUTE); 53 | return year + "年" + (time.get(Calendar.MONTH) + 1) + "月" + 54 | time.get(Calendar.DAY_OF_MONTH) + "日" + 55 | (hour < 10 ? "0" + hour : "" + hour) 56 | + ":" + 57 | (minute < 10 ? "0" + minute : "" + minute); 58 | } else { // 默认返回值 59 | return (time.get(Calendar.MONTH) + 1) + "月" + time.get(Calendar.DAY_OF_MONTH) + "日"; 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/csw/xposedclipboard/util/MyToast.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.Drawable; 6 | import android.graphics.drawable.GradientDrawable; 7 | import android.util.TypedValue; 8 | import android.view.Gravity; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | import android.widget.Toast; 14 | 15 | import com.csw.xposedclipboard.R; 16 | 17 | /** 18 | * Created by 丛 on 2018/5/31 0031. 19 | */ 20 | public class MyToast { 21 | 22 | public static void show(Context context, Drawable icon, String text) { 23 | float size1Dp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, 24 | context.getResources().getDisplayMetrics()); 25 | 26 | LinearLayout layout = new LinearLayout(context); 27 | layout.setOrientation(LinearLayout.HORIZONTAL); 28 | layout.setLayoutParams(new LinearLayout.LayoutParams( 29 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 30 | 31 | GradientDrawable bg = new GradientDrawable(); 32 | bg.setCornerRadius(20 * size1Dp); 33 | bg.setColor(Color.parseColor("#E91E63")); // colorAccent 34 | layout.setBackground(bg); 35 | 36 | if (icon != null) { 37 | ImageView iv = new ImageView(context); 38 | LinearLayout.LayoutParams ivParams = 39 | new LinearLayout.LayoutParams((int) (size1Dp * 30), (int) (size1Dp * 30)); 40 | ivParams.gravity = Gravity.CENTER_VERTICAL; 41 | ivParams.setMargins((int) (10 * size1Dp), (int) (10 * size1Dp), 0, (int) (10 * size1Dp)); 42 | iv.setLayoutParams(ivParams); 43 | iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 44 | iv.setImageDrawable(icon); 45 | 46 | layout.addView(iv); 47 | } 48 | 49 | TextView tv = new TextView(context); 50 | LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams( 51 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 52 | tvParams.gravity = Gravity.CENTER_VERTICAL; 53 | tvParams.setMargins((int) (10 * size1Dp), (int) (10 * size1Dp), (int) (10 * size1Dp), (int) (10 * size1Dp)); 54 | tv.setLayoutParams(tvParams); 55 | tv.setTextColor(Color.WHITE); 56 | tv.setText(text); 57 | 58 | layout.addView(tv); 59 | 60 | Toast toast = new Toast(context); 61 | toast.setView(layout); 62 | toast.setDuration(Toast.LENGTH_LONG); 63 | toast.show(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/drawer_github_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/drawable/drawer_github_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/drawer_record_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/drawable/drawer_record_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/drawer_toast_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/drawable/drawer_toast_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_popup_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/drawable/menu_popup_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/toast_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 17 | 18 | 24 | 25 | 33 | 34 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 60 | 61 | 62 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/clip_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 12 | 19 | 20 | 24 | 25 | 39 | 40 | 52 | 53 | 69 | 70 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/drawer_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 16 | 17 | 31 | 32 | 49 | 50 | 64 | 65 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/drawer_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toast_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_copy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #E91E63 7 | #C2185B 8 | #FF5252 9 | #2F000000 10 | #BDBDBD 11 | #757575 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #E91E63 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 监视剪切板 3 | 4 | open 5 | close 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/test/java/com/csw/xposedclipboard/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.csw.xposedclipboard; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.1.2' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | maven { url "https://jitpack.io" } 21 | google() 22 | jcenter() 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/congshengwu/Xposed_Clipboard/aa14194e16553e5a07442066e0180b9c19b61a56/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 22 21:39:56 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------