I want to get web page source(which is written by me in php) then it shows in textview. However, it returns always null.
I use permisson(INTERNET) but It doesn't work.
When I run this app, TextView shows: "Kaynak Kod: null"
Here is my Activity Codes:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.textView1);
Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
try {
String source = getData("http://www.oeaslan.com/excel/index_.php?gun=1");
tv.setText("Kaynak Kod: "+source);
} catch (Exception e) {
tv.setText("Hata: "+e.getMessage());
}
}
});
}
private String getData(String url){
try{
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
String html = "";
InputStream in = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null)
{
str.append(line);
}
in.close();
html = str.toString();
return html;
}catch(Exception e){
return e.getMessage();
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.omer.text"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Regards.
You have a NetworkOnMainThreadException Look in the LogCat to see it. You have to place your code in an AsyncTask or thread.
You can give something like this a try:
HttpGet request = new HttpPost(url);
HttpResponse response = httpclient.execute(request);
String responseBody = EntityUtils.toString(response.getEntity());
All you have to do is include this method in your code :
public static String getSourceCodeOfWebsite(String urlget){
String fetched_data ="";
try {
URL url = null;
url = new URL(urlget);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
StringBuilder response = new StringBuilder(50000);
InputStream inputStream = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream));
int i = 0;
while ((i = rd.read()) > 0) {
response.append((char)i);
}
fetched_data = response.toString();
} catch (Exception e) {
e.printStackTrace();
}
return fetched_data;
}
pass in the URL as parameter and it returns the code
Related
Specifically I am looking to upload a file with extension .xls
I have a project that tries to do this, but the following error exists
E/AndroidRuntime: FATAL EXCEPTION: Thread-6
Process: com.example.excelpromodel, PID: 12651
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/client/methods/HttpPut;
at com.dropbox.client2.DropboxAPI.putFileRequest(DropboxAPI.java:2390)
at com.dropbox.client2.DropboxAPI.putFileOverwriteRequest(DropboxAPI.java:1760)
at com.dropbox.client2.DropboxAPI.putFileOverwrite(DropboxAPI.java:1726)
at com.example.excelpromodel.SQLite2ExcelActivity$4.run(SQLite2ExcelActivity.java:267)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.ClassNotFoundException: Didn't find class "org.apache.http.client.methods.HttpPut" on path: DexPathList[[zip file "/data/app/com.example.excelpromodel-pu6SR7F9dUiyu9bWnHwX8w==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.excelpromodel-pu6SR7F9dUiyu9bWnHwX8w==/lib/arm, /system/lib, /system/vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at com.dropbox.client2.DropboxAPI.putFileRequest(DropboxAPI.java:2390)
at com.dropbox.client2.DropboxAPI.putFileOverwriteRequest(DropboxAPI.java:1760)
at com.dropbox.client2.DropboxAPI.putFileOverwrite(DropboxAPI.java:1726)
at com.example.excelpromodel.SQLite2ExcelActivity$4.run(SQLite2ExcelActivity.java:267)
at java.lang.Thread.run(Thread.java:764)
My code is:
public class SQLite2ExcelActivity extends AppCompatActivity {
public static Button button1;
public static String path = Environment.getExternalStorageDirectory().getPath() + "/Backup/";
public static File Dir = new File(path);
public void onClickBut1(View v) {
UploadToDropboxFromPath(path + "test.txt", "excel/test.txt");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_2_xl);
button1 = findViewById(R.id.button1);
initViews();
AndroidAuthSession session = buildSession();
dropboxAPI = new DropboxAPI<AndroidAuthSession>(session);
}
static DropboxAPI<AndroidAuthSession> dropboxAPI;
private static final String APP_KEY = "";
private static final String APP_SECRET = "";
private static final String ACCESSTOKEN = "";
private DropboxAPI.UploadRequest request;
private AndroidAuthSession buildSession()
{
AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeyPair);
session.setOAuth2AccessToken(ACCESSTOKEN);
return session;
}
static final int UploadFromSelectApp = 9501;
static final int UploadFromFilemanager = 9502;
public static String DropboxUploadPathFrom = "";
public static String DropboxUploadName = "";
public static String DropboxDownloadPathFrom = "";
public static String DropboxDownloadPathTo = "";
private void UploadToDropboxFromPath (String uploadPathFrom, String uploadPathTo)
{
Toast.makeText(getApplicationContext(), "Upload file ...", Toast.LENGTH_SHORT).show();
final String uploadPathF = uploadPathFrom;
final String uploadPathT = uploadPathTo;
Thread th = new Thread(new Runnable()
{
public void run()
{
File tmpFile = null;
try
{
tmpFile = new File(uploadPathF);
}
catch (Exception e) {e.printStackTrace();}
FileInputStream fis = null;
try
{
fis = new FileInputStream(tmpFile);
}
catch (FileNotFoundException e) {e.printStackTrace();}
try
{
dropboxAPI.putFileOverwrite(uploadPathT, fis, tmpFile.length(), null);
}
catch (Exception e) {}
getMain().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "File successfully uploaded.", Toast.LENGTH_SHORT).show();
}
});
}
});
th.start();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if (requestCode == UploadFromFilemanager)
{
final Uri currFileURI = intent.getData();
final String pathFrom = currFileURI.getPath();
Toast.makeText(getApplicationContext(), "Upload file ...", Toast.LENGTH_SHORT).show();
Thread th = new Thread(new Runnable()
{
public void run()
{
getMain().runOnUiThread(new Runnable()
{
#Override
public void run()
{
UploadToDropboxFromPath(pathFrom, "/db-test/" + DropboxUploadName + pathFrom.substring(pathFrom.lastIndexOf('.')));
Toast.makeText(getApplicationContext(), "File successfully uploaded.", Toast.LENGTH_SHORT).show();
}
});
}
});
th.start();
}...
}
public String getPath(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA, MediaStore.Video.Media.DATA, MediaStore.Audio.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
if(s!=null) {
cursor.close();
return s;
}
}
catch(Exception e){}
try {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
if(s!=null) {
cursor.close();
return s;
}
}
catch(Exception e){}
try {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
String s = cursor.getString(column_index);
cursor.close();
return s;
}
finally {
if (cursor != null) {
cursor.close();
}
}
}
public SQLite2ExcelActivity getMain()
{
return this;
}
AndroidManifest..
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.excelpromodel">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:configChanges="orientation|keyboard"
android:launchMode="singleTask" >
<intent-filter>
<data android:scheme="db-akg125xzg45a9gc" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".SQLite2ExcelActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme" />
<activity
android:name=".Excel2SQLiteActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme" />
</application>
</manifest>
and dependences
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.ajts.androidmads.SQLite2Excel:library:1.0.4'
implementation 'com.ajts.androidmads.sqliteimpex:library:1.0.0'
implementation files('libs/dropbox-android-sdk-1.6.3.jar')
implementation files('libs/json_simple-1.1.jar')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
get and upload to Dropbox the xls file that is in the "Backup" path with a single button and not from the file manager. Thank you all
I'm trying to make a connection with a python server I made but everytime I press the button my app crashes.
Here is my code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
String ip = "<IP>";
int port = <PORT>;
try {
Socket s = new Socket(ip, port);
System.out.println("connected!");
s.close();
} catch (IOException e) {
System.out.println(e);
}
}
});
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
I really don't understand what went wrong
You are doing network on main UI thread which is not allowed. So use async Task and do this task in background thread. For that, create a class (for ex. background.java )and use Async task in it.
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
background bg = new background();
bg.execute();
}
});
and in your background class:
public class background extends AsyncTask<Void,Void,Void> {
#Override
protected Void doInBackground(Void... params) {
String ip = "<IP>";
int port = <PORT>;
try {
Socket s = new Socket(ip, port);
System.out.println("connected!");
s.close();
} catch (IOException e) {
System.out.println(e);
}
return null;
}
}
Hope this helps :)
I'm currently starting to develop apps for android but I'm currently stuck with an unknownhostexception.
Here is my code:
...
protected class FetchWeatherTask extends AsyncTask <String, Void, Void>{
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
protected Void doInBackground(String... params) {
//initialize Connection and reader
HttpURLConnection urlconnection=null;
BufferedReader reader=null;
String forecastJsonStr =null;
String format = "json";
String units = "metric";
int numDays = 7;
try{
final String BASE_URL = "http://apikey.openweathermap.org/data/2.5/forecast/daily";
final String QUERY_PARAM="zip";
final String FORMAT_PARAM= "mode";
final String UNITS_PARAM= "units";
final String DAYS_PARAM= "cnt";
final String APPID_PARAM="APPID";
//make Connection to the OpenWeatherURL
//IDEA: API-Code for future use as parameter of the method
//String apikey = "&APPID="+BuildConfig.OPEN_WEATHER_MAP_API_KEY;
//String baseUrl="http://apikey.openweathermap.org/data/2.5/forecast/daily?zip=94043&mode=json&units=metric&cnt=7";
//URL url= new URL(baseUrl.concat(apikey));
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM,params[0])
.appendQueryParameter(FORMAT_PARAM,format)
.appendQueryParameter(UNITS_PARAM,units)
.appendQueryParameter(DAYS_PARAM,Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM,BuildConfig.OPEN_WEATHER_MAP_API_KEY)
.build();
URL url = new URL(builtUri.toString());
//URL url = new URL("http://apikey.openweathermap.org/data/2.5/forecast/daily?zip=94043&mode=json&units=metric&cnt=7&APPID=31d96db6578ca2e94f31714e882118be");
Log.v(LOG_TAG, "Built URI "+ builtUri.toString());
urlconnection= (HttpURLConnection) url.openConnection();
urlconnection.setRequestMethod("GET");
urlconnection.connect();
//Read inputStream into a buffer
InputStream input = urlconnection.getInputStream();
StringBuffer buffer= new StringBuffer();
if(input==null){
return null;
}
reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line=reader.readLine())!=null){
buffer.append(line+"\n");
}
if (buffer.length()==0){
return null;
}
forecastJsonStr=buffer.toString();
}
catch(IOException e){
Log.e("ForecastFragment","Error",e);
return null;
}finally {
if(urlconnection==null){
urlconnection.disconnect();
}
if(reader!=null){
try{
reader.close();
} catch (IOException e) {
Log.e("ForecastFragment","Error",e);
}
}
return null;
}
}
}
I have granted internet access permissions for this app as well in my android manifest, but it's still causes this exception. Here the manifest.xml for review purpose:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cc_student.sunshine.app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Below is my code for MainActivity.java.The error according to toasts is in creating directory.
MainActivity.java
#Override
protected void onActivityResult(int requestcode,int resultcode,Intent data){
super.onActivityResult(requestcode,resultcode,data);
if (requestcode == TAKE_PICTURE)
{
if(resultcode== Activity.RESULT_OK){
ImageView imageHolder = (ImageView)findViewById(R.id.image_camera);
Bitmap bitmap = (Bitmap)data.getExtras().get("data");
String partFilename = currentDateFormat();
storeCameraPhotoInSDCard(bitmap, partFilename);
// display the image from SD Card to ImageView Control
String storeFilename = "photo_" + partFilename + ".jpg";
Bitmap mBitmap = getImageFileFromSDCard(storeFilename);
imageHolder.setImageBitmap(mBitmap);
}
}
}
private String currentDateFormat(){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");
String currentTimeStamp = dateFormat.format(new Date(0));
return currentTimeStamp;
}
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(MainActivity.this, "WriteMode ON", Toast.LENGTH_SHORT).show();
return true;
}
Toast.makeText(MainActivity.this, "WriteMode OFF", Toast.LENGTH_SHORT).show();
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
Toast.makeText(MainActivity.this, "Mounted or ReadMode", Toast.LENGTH_SHORT).show();
return true;
}
Toast.makeText(MainActivity.this, "no-Mounted or no-ReadMode", Toast.LENGTH_SHORT).show();
return false;
}
private void storeCameraPhotoInSDCard(Bitmap bitmap, String currentDate){
boolean isAvailable=isExternalStorageWritable();
if(isAvailable){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,90, bytes);
String imgUri = "photo_" + currentDate + ".jpg";
File appDirectory = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages");
boolean success = appDirectory.mkdirs();
if (success) {
Toast.makeText(MainActivity.this, "Directory Created", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Failed - Error", Toast.LENGTH_SHORT).show();
}
File destination = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages/"+imgUri);
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private Bitmap getImageFileFromSDCard(String filename){
File storageDir = new File(Environment.getExternalStorageDirectory() + "/", "CountDotsAppImages");
Bitmap bitmap = null;
File imageFile = new File(storageDir.getPath()+File.separator + filename);
try {
FileInputStream fis = new FileInputStream(imageFile);
Toast.makeText(MainActivity.this, imageFile.toString() , Toast.LENGTH_LONG).show();
bitmap = BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> permission is added
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.countdots"
android:versionCode="1"
android:versionName="1.0" android:installLocation="auto">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Toasts Output :
Mounted or ReadMode
WriteMode ON
Directory Does Not Exist, Create It
Failed -Error //Error in creating directory mkdir
I tried using both mkdir() and mkdirs()
Figured it out.
As, I was compiling with Android 6.0. It requires user to grant permission.
So,following code should be inserted and checked if user grants app permission or not.Then if user grants permission to read and write manifest will be updated and volia !!!
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE},
1);
} else {
//do something
}
} else {
//do something
}
This code works for me
try{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,90, bytes);
imgUri = "photo_" + System.currentTimeMillis() + ".jpg";
File appDirectory = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages");
appDirectory.mkdirs();
File destination = new File(Environment.getExternalStorageDirectory(),"CountDotsAppImages/"+imgUri);
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
For adding directory you can use this method.
isAvailable=ExternalStorageChecker.isExternalStorageWritable();
if(isAvailable){
dir = new File(myContext.getExternalFilesDir(null), newAlbumDir.getText().toString().trim());
if(!dir.mkdirs()){
Log.e("++++++","Directoy Already Exist");
Log.e("External Directory Path","++++"+dir.getAbsolutePath());
}
else{
Log.e("++++","Directory Created");
Toast.makeText(myContext,"File Created on External",Toast.LENGTH_SHORT).show();
Log.e("Externa Directory Path","++++"+dir.getAbsolutePath());
}
}
else{
Toast.makeText(myContext,"File Created on Internal",Toast.LENGTH_SHORT).show();
Log.e("Internal Directory Path","++++"+myContext.getFilesDir().getPath());
dir=new File(myContext.getFilesDir(),newAlbumDir.getText().toString());
}
After it created the directory(dir) you can use to create the File.
Objective: send a ping to android clients. I have an array of device registration Id's held in my user object.
In GCMIntentService.java, auto created within my app, I get that registration id here
/**
* Called back when a registration token has been received from the Google
* Cloud Messaging service.
*
* #param context
* the Context
*/
#Override
public void onRegistered(Context context, String registration) {
Log.d(TAG, "onRegistered(context, registration), Registration: " + registration);
and then create the DeviceInfo object (also pre defined with app engine) and then add this ID to the user through another endpoint. I have confirmed this works/ see the string held and assume that my device is now registered properly.
When certain things happen in the backend, I have a custom notification class and run this method:
public void sendNotificationPingToUsers(
#Named("userIds") ArrayList<Long> userIds,
ZeppaNotification notification) throws IOException {
Sender sender = new Sender(Constants.SENDER_ID);
PersistenceManager mgr = getPersistenceManager();
try {
ArrayList<String> allDevices = new ArrayList<String>();
for (int i = 0; i < userIds.size(); i++) {
long userId = userIds.get(i);
ZeppaUser zeppaUser = mgr
.getObjectById(ZeppaUser.class, userId);
if (zeppaUser != null) {
ZeppaNotification specificNotification = new ZeppaNotification();
specificNotification.setToUserId(userId);
specificNotification.setFromUserId(notification
.getFromUserId());
specificNotification.setEventId(notification.getEventId());
specificNotification.setExtraMessage(notification
.getExtraMessage());
specificNotification.setNotificationType(notification
.getType());
String extraMessage = specificNotification
.getExtraMessage();
if (extraMessage.length() > 1000) {
extraMessage = extraMessage.substring(0, 1000)
+ "[...]";
}
mgr.makePersistent(specificNotification);
allDevices.addAll(zeppaUser.getDevices());
}
}
if (!allDevices.isEmpty()) {
Message msg = new Message.Builder().collapseKey("sendToSync")
.build();
MulticastResult result = sender.send(msg, allDevices, 5);
result.getTotal();
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
mgr.close();
}
}
I pass in the other notification so I can recreate it for all users, hold it in the notification table, then ping the device so that it can pull this and any others unseen and create a status bar notification.
This method, again in GCMIntentService:
#Override
public void onMessage(Context context, Intent intent) {
Log.d(TAG, "received message ping");
Is never called and this is where I am trying to handle everything from the device side of things. Can anyone point out what I may be doing wrong or if I am incorrectly interpreting the way this service works?
Thank you
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<permission
android:name="com.minook.zeppa.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.minook.zeppa.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:name=".ZeppaApplication"
android:allowBackup="true"
android:icon="#drawable/zeppa_icon"
android:label="#string/app_name"
android:testOnly="false"
android:theme="#style/ZeppaTheme"
android:uiOptions="none" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".LoginActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".CreateAccountActivity"
android:label="#string/create_account"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".NewFriendsActivity"
android:label="#string/add_friends"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
</activity>
<activity
android:name=".EventViewActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".NewEventActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".UserActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".ZeppaPreferenceActivity"
android:label="#string/event_details"
android:logo="#drawable/zeppa_icon" >
</activity>
<!--
<activity
android:name=".RegisterActivity"
android:launchMode="singleTop" >
</activity>
-->
<service android:name=".GCMIntentService" />
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.minook.zeppa" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.minook.zeppa" />
</intent-filter>
</receiver>
</application>
Another Note: i have tried using the project number and a server key generated by the GAE console with no specified IP. Neither have worked so far.
I just realized I never came back to this.
Turns out that he app-engine created GCM code isn't the ideal way to do it. This is is the essential code in my application with now successfully sends a send-to-sync from the backend and displays a notification in the status bar.
public class ZeppaGCMReceiver extends WakefulBroadcastReceiver {
final private static String TAG = "GCMIntentService";
private static String registrationId = null;
public static void register(final ZeppaApplication application) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
.getApplicationContext());
try {
registrationId = gcm.register(Constants.PROJECT_NUMBER);
Log.d(TAG, "gcm.register( " + registrationId + " )");
ZeppaUser currentUser = ZeppaUserSingleton.getInstance().getUser();
if (currentUser.getDevices() == null
|| !currentUser.getDevices().contains(registrationId)) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Zeppauserendpoint.Builder endpointBuilder = new Zeppauserendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
application.getGoogleAccountCredential());
endpointBuilder = CloudEndpointUtils
.updateBuilder(endpointBuilder);
Zeppauserendpoint userEndpoint = endpointBuilder
.build();
try {
RegisterUserDevice registerTask = userEndpoint
.registerUserDevice(
ZeppaUserSingleton.getInstance().getUserId(),
registrationId);
registerTask.execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}.execute();
} else {
Log.d(TAG, "Already Registered");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void unregister(final ZeppaApplication application) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
.getApplicationContext());
// TODO: registration id in preferences and
try {
gcm.unregister();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "received message ping");
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String messageType = gcm.getMessageType(intent);
Log.d(TAG, "MessageType: " + messageType);
if (messageType == null) {
Log.d(TAG, "Message is null");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
.equals(messageType)) {
Log.d(TAG, "Error!");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
Log.d(TAG, "Deleted");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
.equals(messageType)) {
Log.d(TAG, "Message");
handlePingInAsync(context);
} else {
Log.d(TAG, "WTF are you..? " + intent.toString());
}
}
private void handlePingInAsync(Context context) {
Context[] param = {context};
new AsyncTask<Context, Void, Void>() {
#Override
protected Void doInBackground(Context... params) {
Context context = params[0];
GoogleAccountCredential credential = getCredential(context);
if (credential == null) {
return null;
}
Zeppanotificationendpoint.Builder endpointBuilder = new Zeppanotificationendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(), credential);
endpointBuilder = CloudEndpointUtils
.updateBuilder(endpointBuilder);
Zeppanotificationendpoint notificationEndpoint = endpointBuilder
.build();
try {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SHARED_PREFS, Context.MODE_PRIVATE);
Long userId = prefs.getLong(Constants.USER_ID, -1);
if (userId > 0) {
GetUnseenNotifications getUnseenNotifications = notificationEndpoint
.getUnseenNotifications(userId);
CollectionResponseZeppaNotification collectionResponse = getUnseenNotifications
.execute();
if (collectionResponse == null
|| collectionResponse.getItems() == null) {
} else {
List<ZeppaNotification> notifications = collectionResponse
.getItems();
sendNotificationsForResult(notifications,
context);
try {
NotificationSingleton.getInstance()
.addAllNotifcations(notifications);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
} else {
Log.d(TAG, "No Set userId");
}
} catch (IOException ioEx) {
ioEx.printStackTrace();
}
return null;
}
}.execute(param);
}
private GoogleAccountCredential getCredential(Context context) {
GoogleAccountCredential credential = ((ZeppaApplication) context.getApplicationContext())
.getGoogleAccountCredential();
if (credential == null) {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SHARED_PREFS, Context.MODE_PRIVATE);
String email = prefs.getString(Constants.EMAIL_ADDRESS, null);
if (email != null && !email.isEmpty() && Constants.IS_CONNECTED) {
credential = GoogleAccountCredential.usingAudience(context,
Constants.APP_ENGINE_AUDIENCE_CODE);
credential.setSelectedAccountName(email);
return credential;
}
return null;
} else {
return credential;
}
}
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
private void sendNotificationsForResult(List<ZeppaNotification> resultList,
Context context) {
Log.d(TAG, "trying to send Notifications for result");
Notification.Builder notifBuilder = new Notification.Builder(context);
if (resultList.size() > 1) {
notifBuilder.setContentTitle(resultList.size()
+ " new notifications");
StringBuilder stringBuilder = new StringBuilder();
for (ZeppaNotification notification : resultList) {
stringBuilder.append(notification.getExtraMessage()).append(
'\n');
}
notifBuilder.setContentText(stringBuilder.toString());
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, true);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
notifBuilder.setContentIntent(pendingIntent);
} else {
ZeppaNotification notification = resultList.get(0);
manageSingleNotification(context, notification, notifBuilder);
notifBuilder.setContentText(notification.getExtraMessage());
}
notifBuilder.setLights(Color.CYAN, 750, 3000);
notifBuilder.setAutoCancel(true);
notifBuilder.setSmallIcon(R.drawable.notif_ic_zeppa);
Notification notification = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
notifBuilder.setPriority(Notification.PRIORITY_DEFAULT);
notification = notifBuilder.build();
} else {
notification = notifBuilder.getNotification();
}
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Log.d(TAG, "Notification Should Post");
notificationManager.notify(0, notification);
}
private void manageSingleNotification(Context context,
ZeppaNotification notification, Notification.Builder builder) {
Intent intent = null;
switch (notification.getNotificationOrdinal()) {
case 0:
builder.setContentTitle("New Friend Request");
intent = new Intent(context, NewFriendsActivity.class);
break;
case 1:
builder.setContentTitle("New Connection");
intent = new Intent(context, UserActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_USER_ID,
notification.getFromUserId());
break;
case 2:
builder.setContentTitle("Event Recommendation");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 3:
builder.setContentTitle("New Invite");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 4:
builder.setContentTitle("Event Comment");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 5:
builder.setContentTitle("Event Canceled");
intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
break;
case 6:
builder.setContentTitle("Event Updated");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 7:
builder.setContentTitle("Friend Joined Event");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 8:
builder.setContentTitle("Friend Left Event");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 9:
builder.setContentTitle("Let's Find a Time?");
break;
case 10:
builder.setContentTitle("Time Found!");
break;
case 11:
builder.setContentTitle("Event Reposted");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
default: // this shouldnt happen
builder.setContentTitle("New Zeppa Notification");
intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
break;
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
builder.setContentIntent(pendingIntent);
}
}
And then my Manifest needed:
<permission
android:name="package.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="package.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<receiver
android:name="package.ZeppaGCMReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="package.GCMIntentService" />
</intent-filter>
</receiver>
<service
android:name="package.ZeppaGCMService"
android:enabled="true" />
Then, finally, from my endpoints class, when certain things were entered into the database, I determined which users should be notified, and fired this method:
NOTE: getDevices only returns the android device IDS. I got rid of the DeviceInfo class, it didn't seem useful but that should be the improper way of handling this. iOS is handled differently as I am sure you are aware. Will update if I change this/ if people want to see the iOS implementation.
public void sendNotificationPingToUsers(
#Named("userIds") List<Long> userIds,
ZeppaNotification notification) {
Sender sender = new Sender(Constants.SENDER_ID);
PersistenceManager mgr = getPersistenceManager();
try {
List<String> allDevices = new ArrayList<String>();
for (int i = 0; i < userIds.size(); i++) {
long userId = userIds.get(i);
ZeppaUser zeppaUser = mgr
.getObjectById(ZeppaUser.class, userId);
if (zeppaUser != null) {
ZeppaNotification specificNotification = new ZeppaNotification();
specificNotification.setToUserId(userId);
specificNotification.setFromUserId(notification
.getFromUserId());
specificNotification.setEventId(notification.getEventId());
specificNotification.setExtraMessage(notification
.getExtraMessage());
specificNotification.setNotificationType(notification
.getType());
mgr.makePersistent(specificNotification);
allDevices.addAll(zeppaUser.getDevices());
}
}
if (!allDevices.isEmpty()) {
Message msg = new Message.Builder().collapseKey("sendToSync")
.build();
MulticastResult result = sender.send(msg, allDevices, 500);
result.getTotal();
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
mgr.close();
}
}