├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mega4tech │ │ └── whatsappapi │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── mega4tech │ │ │ └── whatsappapi │ │ │ ├── ContactCardRecyclerViewAdapter.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable │ │ └── ic_backspace_black_24dp.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── contact_card.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── mega4tech │ └── whatsappapi │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── whatsappapilibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── mega4tech │ └── whatsappapilibrary │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ ├── mega4tech │ │ └── whatsappapilibrary │ │ │ ├── Utils.java │ │ │ ├── WhatsappApi.java │ │ │ ├── exception │ │ │ ├── RootNotAvailableException.java │ │ │ └── WhatsappNotInstalledException.java │ │ │ ├── liseteners │ │ │ ├── GetContactsListener.java │ │ │ └── SendMessageListener.java │ │ │ └── model │ │ │ ├── WContact.java │ │ │ └── WMessage.java │ │ └── whatsapp │ │ └── MediaData.java └── res │ └── values │ └── strings.xml └── test └── java └── com └── mega4tech └── whatsappapilibrary └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | .idea 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/vcs.xml 7 | *.apk 8 | /app/fabric.properties 9 | /.idea/libraries 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Whatsapp-API 2 | 3 | An Android Library with demo application, to send media and text messages via Whatsapp on rooted device 4 | 5 | ## Installation 6 | 7 | Add it in your root build.gradle at the end of repositories: 8 | 9 | ``` 10 | allprojects { 11 | repositories { 12 | ... 13 | maven { url 'https://jitpack.io' } 14 | } 15 | } 16 | ``` 17 | Add the dependency 18 | ``` 19 | dependencies { 20 | compile 'com.github.omegaes:Whatsapp-API:1.0.3' 21 | } 22 | ```` 23 | 24 | 25 | ## Usage 26 | 27 | Check if device has whatsapp version 28 | 29 | ``` 30 | WhatsappApi.getInstance().isWhatsappInstalled() -> boolean 31 | ``` 32 | 33 | Check if device has root privilege 34 | 35 | ``` 36 | WhatsappApi.getInstance().isRootAvailable() -> boolean 37 | ``` 38 | 39 | Get list of whatsapp contacts, from whatsapp database 40 | 41 | ``` 42 | WhatsappApi.getInstance().getContacts(Context, GetContactsListener) -> void 43 | ``` 44 | 45 | Send message to one contact or list of contacts, create WMessage and WContact objects ! 46 | ``` 47 | WhatsappApi.getInstance().sendMessage(List, WMessage, Context, SendMessageListener) -> void 48 | ``` 49 | 50 | 51 | ## Contributing 52 | 53 | 1. Fork it! 54 | 2. Create your feature branch: `git checkout -b my-new-feature` 55 | 3. Commit your changes: `git commit -am 'Add some feature'` 56 | 4. Push to the branch: `git push origin my-new-feature` 57 | 5. Submit a pull request :D 58 | 59 | ## History 60 | 61 | Not yet 62 | 63 | ## Author 64 | 65 | * **Abdulrahman Babil** - *Software engineer* - [Mega4Tech](http://mega4tech.com) 66 | 67 | ## License 68 | 69 | This project is licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3 - see the [LICENSE](LICENSE) file for details 70 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.mega4tech.whatsappapi" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.2.0' 28 | testCompile 'junit:junit:4.12' 29 | compile project(':whatsappapilibrary') 30 | compile 'com.miguelgaeta.android-media-picker:media-picker:1.5.0' 31 | compile 'org.apache.commons:commons-lang3:3.4' 32 | compile "commons-io:commons-io:2.4" 33 | compile 'com.android.support:design:25.2.0' 34 | compile 'com.android.support:recyclerview-v7:25.2.0' 35 | compile 'gun0912.ted:tedpermission:1.0.3' 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/aboodba/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keepattributes *Annotation* 20 | -keepclassmembers class ** { 21 | @com.squareup.otto.Subscribe public *; 22 | @com.squareup.otto.Produce public *; 23 | } 24 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mega4tech/whatsappapi/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.mega4tech.whatsappapi; 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 | * Instrumentation 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() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.mega4tech.whatsappapi", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/mega4tech/whatsappapi/ContactCardRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.mega4tech.whatsappapi; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.mega4tech.whatsappapilibrary.model.WContact; 13 | 14 | import java.util.HashMap; 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | 18 | public class ContactCardRecyclerViewAdapter extends RecyclerView.Adapter { 19 | private RecycleItemClickListener mItemClickListener; 20 | private List mObjects = new LinkedList<>(); 21 | HashMap mDictionary; 22 | private Context mContext; 23 | private LayoutInflater layoutInflater; 24 | String[] mContacts; 25 | boolean[] mSelectedContacts; 26 | 27 | public ContactCardRecyclerViewAdapter(Context context,List items, String[] contacts, boolean[] selectedContacts, HashMap dictionary) { 28 | this.mObjects = items; 29 | this.mContext = context; 30 | this.layoutInflater = LayoutInflater.from(context); 31 | mContacts = contacts; 32 | mSelectedContacts = selectedContacts; 33 | mDictionary = dictionary; 34 | } 35 | 36 | 37 | @Override 38 | public int getItemCount() { 39 | return this.mObjects.size(); 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(ContactCardRecyclerViewAdapter.ViewHolder holder, int position) { 44 | 45 | WContact item = this.mObjects.get(position); 46 | Log.d("ABDULL55", item.toString()); 47 | 48 | holder.contactNameTv.setText(item.getName()); 49 | holder.contactRemoveIv.setTag(item); 50 | holder.contactRemoveIv.setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | WContact contact = (WContact) v.getTag(); 54 | if(mDictionary.containsKey(contact)) 55 | mSelectedContacts[mDictionary.get(contact)] = false; 56 | mObjects.remove(contact); 57 | mDictionary.remove(contact); 58 | notifyDataSetChanged(); 59 | } 60 | }); 61 | Log.d("ABDULL!", item.toString()); 62 | 63 | } 64 | 65 | 66 | @Override 67 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 68 | final LayoutInflater mInflater = LayoutInflater.from(parent.getContext()); 69 | final View sView = mInflater.inflate(R.layout.contact_card, parent, false); 70 | return new ContactCardRecyclerViewAdapter.ViewHolder(sView, mItemClickListener); 71 | } 72 | 73 | class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 74 | private RecycleItemClickListener mItemClickListener; 75 | private TextView contactNameTv; 76 | private ImageView contactRemoveIv; 77 | 78 | 79 | public ViewHolder(View view, RecycleItemClickListener itemClickListener) { 80 | super(view); 81 | contactNameTv = (TextView) view.findViewById(R.id.contact_name_tv); 82 | contactRemoveIv = (ImageView) view.findViewById(R.id.contact_remove_iv); 83 | mItemClickListener = itemClickListener; 84 | view.setOnClickListener(this); 85 | } 86 | 87 | @Override 88 | public void onClick(View v) { 89 | if (mItemClickListener != null) { 90 | mItemClickListener.onItemClick(v, getPosition()); 91 | } 92 | } 93 | } 94 | 95 | public void setOnItemClickListener(RecycleItemClickListener listener) { 96 | this.mItemClickListener = listener; 97 | } 98 | 99 | public interface RecycleItemClickListener { 100 | public void onItemClick(View view, int position); 101 | } 102 | 103 | public void setmObjects(List mObjects) { 104 | this.mObjects = mObjects; 105 | notifyDataSetChanged(); 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/mega4tech/whatsappapi/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mega4tech.whatsappapi; 2 | 3 | import android.Manifest; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AlertDialog; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.DefaultItemAnimator; 11 | import android.support.v7.widget.LinearLayoutManager; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.text.TextUtils; 14 | import android.util.Log; 15 | import android.view.View; 16 | import android.widget.Button; 17 | import android.widget.EditText; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | 21 | import com.gun0912.tedpermission.PermissionListener; 22 | import com.gun0912.tedpermission.TedPermission; 23 | import com.mega4tech.whatsappapilibrary.WhatsappApi; 24 | import com.mega4tech.whatsappapilibrary.exception.WhatsappNotInstalledException; 25 | import com.mega4tech.whatsappapilibrary.liseteners.GetContactsListener; 26 | import com.mega4tech.whatsappapilibrary.liseteners.SendMessageListener; 27 | import com.mega4tech.whatsappapilibrary.model.WContact; 28 | import com.mega4tech.whatsappapilibrary.model.WMessage; 29 | import com.miguelgaeta.media_picker.MediaPicker; 30 | import com.miguelgaeta.media_picker.RequestType; 31 | 32 | import java.io.File; 33 | import java.io.IOException; 34 | import java.util.ArrayList; 35 | import java.util.HashMap; 36 | import java.util.LinkedList; 37 | import java.util.List; 38 | 39 | public class MainActivity extends AppCompatActivity implements View.OnClickListener, MediaPicker.Provider, MediaPicker.OnError { 40 | 41 | String[] mContacts; 42 | boolean[] mSelectedContacts; 43 | 44 | HashMap mDictionary; 45 | List mAllContacts; 46 | List mReceivers; 47 | File attachmentFile; 48 | 49 | 50 | private RecyclerView mContactsRv; 51 | private Button mAddContactsBtn; 52 | private EditText mMessageTextTv; 53 | private Button mSendMsgBtn; 54 | private TextView mAttachmentTv; 55 | private Button mAddAttachmentBtn; 56 | private ContactCardRecyclerViewAdapter mAdapter; 57 | 58 | 59 | @Override 60 | protected void onCreate(Bundle savedInstanceState) { 61 | super.onCreate(savedInstanceState); 62 | 63 | mDictionary = new HashMap<>(); 64 | mReceivers = new LinkedList<>(); 65 | 66 | if (!WhatsappApi.getInstance().isWhatsappInstalled()) { 67 | Toast.makeText(this, "Whatsapp not installed", Toast.LENGTH_SHORT).show(); 68 | return; 69 | } 70 | 71 | 72 | if (!WhatsappApi.getInstance().isRootAvailable()) { 73 | Toast.makeText(this, "Root is not available", Toast.LENGTH_SHORT).show(); 74 | return; 75 | } 76 | 77 | setContentView(R.layout.activity_main); 78 | initView(); 79 | 80 | mSendMsgBtn.setOnClickListener(this); 81 | mAddContactsBtn.setOnClickListener(this); 82 | mAddAttachmentBtn.setOnClickListener(this); 83 | mAddContactsBtn.setEnabled(false); 84 | mSendMsgBtn.setEnabled(false); 85 | 86 | RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, true); 87 | mContactsRv.setLayoutManager(mLayoutManager); 88 | mContactsRv.setItemAnimator(new DefaultItemAnimator()); 89 | 90 | try { 91 | WhatsappApi.getInstance().getContacts(this, new GetContactsListener() { 92 | @Override 93 | public void receiveWhatsappContacts(List contacts) { 94 | mAllContacts = contacts; 95 | mAddContactsBtn.setEnabled(true); 96 | mSendMsgBtn.setEnabled(true); 97 | mContacts = new String[contacts.size()]; 98 | mSelectedContacts = new boolean[contacts.size()]; 99 | mAdapter = new ContactCardRecyclerViewAdapter(MainActivity.this, mReceivers, mContacts, mSelectedContacts, mDictionary); 100 | mContactsRv.setAdapter(mAdapter); 101 | int i = 0; 102 | for (WContact contact : contacts) { 103 | mContacts[i] = contact.getName();//+ ", " + contact.getId().split("@")[0]; 104 | i++; 105 | } 106 | } 107 | }); 108 | } catch (WhatsappNotInstalledException e) { 109 | e.printStackTrace(); 110 | } 111 | 112 | 113 | } 114 | 115 | private void initView() { 116 | mContactsRv = (RecyclerView) findViewById(R.id.contacts_rv); 117 | mAddContactsBtn = (Button) findViewById(R.id.add_contacts_btn); 118 | mMessageTextTv = (EditText) findViewById(R.id.message_text_tv); 119 | mSendMsgBtn = (Button) findViewById(R.id.send_msg_btn); 120 | mAttachmentTv = (TextView) findViewById(R.id.attachment_tv); 121 | mAddAttachmentBtn = (Button) findViewById(R.id.add_attachment_btn); 122 | 123 | } 124 | 125 | @Override 126 | public void onClick(View v) { 127 | switch (v.getId()) { 128 | case R.id.add_contacts_btn: 129 | new AlertDialog.Builder(this) 130 | .setMultiChoiceItems(mContacts, mSelectedContacts, new DialogInterface.OnMultiChoiceClickListener() { 131 | @Override 132 | public void onClick(DialogInterface dialog, int which, boolean isChecked) { 133 | mSelectedContacts[which] = isChecked; 134 | if (isChecked) { 135 | mReceivers.add(mAllContacts.get(which)); 136 | mDictionary.put(mAllContacts.get(which), which); 137 | } else { 138 | mReceivers.remove(mAllContacts.get(which)); 139 | mDictionary.remove(mAllContacts.get(which)); 140 | 141 | } 142 | } 143 | }) 144 | .setPositiveButton(R.string.ok_button_label, new DialogInterface.OnClickListener() { 145 | public void onClick(DialogInterface dialog, int whichButton) { 146 | dialog.dismiss(); 147 | mAdapter.setmObjects(mReceivers); 148 | 149 | } 150 | }) 151 | .show(); 152 | break; 153 | 154 | case R.id.add_attachment_btn: 155 | new TedPermission(this) 156 | .setPermissionListener(new PermissionListener() { 157 | @Override 158 | public void onPermissionGranted() { 159 | MediaPicker.startForDocuments(MainActivity.this, MainActivity.this); 160 | } 161 | 162 | @Override 163 | public void onPermissionDenied(ArrayList deniedPermissions) { 164 | Toast.makeText(MainActivity.this, "We need \"read file from storage\" permission to select attachment", Toast.LENGTH_SHORT).show(); 165 | } 166 | }) 167 | .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]") 168 | .setPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) 169 | .check(); 170 | break; 171 | case R.id.send_msg_btn: 172 | if (mReceivers.size() < 1) { 173 | Toast.makeText(this, "You should select one receiver at least", Toast.LENGTH_SHORT).show(); 174 | return; 175 | } 176 | if (mReceivers.size() > 5) { 177 | Toast.makeText(this, "You should select less than 5 receivers, demo version !!", Toast.LENGTH_SHORT).show(); 178 | return; 179 | } 180 | if (TextUtils.isEmpty(mMessageTextTv.getText()) && attachmentFile == null) { 181 | Toast.makeText(this, "please enter your message or select a media file to send", Toast.LENGTH_SHORT).show(); 182 | return; 183 | } 184 | String text = (!TextUtils.isEmpty(mMessageTextTv.getText())) ? mMessageTextTv.getText().toString() : ""; 185 | WMessage message = new WMessage(text, attachmentFile, this); 186 | 187 | try { 188 | WhatsappApi.getInstance().sendMessage(mReceivers, message, this, new SendMessageListener() { 189 | @Override 190 | public void finishSendWMessage(List contact, WMessage message) { 191 | Toast.makeText(MainActivity.this, "your message has been sent successfully", Toast.LENGTH_SHORT).show(); 192 | } 193 | }); 194 | } catch (WhatsappNotInstalledException e) { 195 | e.printStackTrace(); 196 | 197 | } catch (IOException e) { 198 | e.printStackTrace(); 199 | } 200 | break; 201 | } 202 | } 203 | 204 | @Override 205 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 206 | super.onActivityResult(requestCode, resultCode, data); 207 | 208 | MediaPicker.handleActivityResult(this, requestCode, resultCode, data, new MediaPicker.OnResult() { 209 | 210 | @Override 211 | public void onError(IOException e) { 212 | Log.e("MediaPicker", "Got file error.", e); 213 | e.printStackTrace(); 214 | attachmentFile = null; 215 | mAttachmentTv.setText(""); 216 | } 217 | 218 | @Override 219 | public void onSuccess(File mediaFile, String mimeType, RequestType request) { 220 | attachmentFile = mediaFile; 221 | mAttachmentTv.setText("Attachment file: " + mediaFile.getName()); 222 | } 223 | 224 | @Override 225 | public void onCancelled() { 226 | Log.e("MediaPicker", "Got cancelled event."); 227 | attachmentFile = null; 228 | mAttachmentTv.setText(""); 229 | } 230 | }); 231 | } 232 | 233 | @Override 234 | public void onError(IOException e) { 235 | e.printStackTrace(); 236 | } 237 | 238 | @Override 239 | public Context getContext() { 240 | return this; 241 | } 242 | 243 | @Override 244 | public File getImageFile() { 245 | return null; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_backspace_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 21 | 22 | 23 | 28 | 29 |