();
26 |
27 | AppAdapter(Context c , Integer[] icons , String[] titles , String[] description ) {
28 | super( c , R.layout.row_layout , R.id.rowTitle , titles );
29 | mContext = c;
30 |
31 | this.icons.addAll(Arrays.asList(icons));
32 | this.titles.addAll(Arrays.asList(titles));
33 | this.description.addAll(Arrays.asList(description));
34 |
35 | }
36 |
37 | @Override
38 | public View getView(int position, View convertView, ViewGroup parent) {
39 | View row = convertView;
40 | AppViewHolder appViewHolder = null;
41 |
42 | if ( row == null ) {
43 | LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
44 | row = layoutInflater.inflate(R.layout.row_layout, parent, false);
45 | appViewHolder = new AppViewHolder(row);
46 | row.setTag(appViewHolder);
47 | //Log.i (LOG_TAG , "New Row!");
48 | } else {
49 | appViewHolder = (AppViewHolder) row.getTag();
50 | //Log.i (LOG_TAG , "Recycling row!");
51 | }
52 |
53 | appViewHolder.icon.setImageResource((Integer) icons.get(position));
54 | appViewHolder.title.setText((String)titles.get(position));
55 | appViewHolder.desc.setText((String)description.get(position));
56 |
57 | return row; //super.getView(position, convertView, parent);
58 | }
59 |
60 | @Override
61 | public int getCount() {
62 | return icons.size();
63 | }
64 |
65 | public void add(Integer i , String title , String desc) {
66 | icons.add(i);
67 | titles.add(title);
68 | description.add(desc);
69 |
70 | this.notifyDataSetChanged();
71 | // Log.i(LOG_TAG, " on click send....");
72 | // Integer cnt = icons.size();
73 | // Log.i(LOG_TAG, " Numero de elementos: " + cnt.toString());
74 | }
75 |
76 | @Override
77 | public void clear() {
78 | icons.clear();
79 | titles.clear();
80 | description.clear();
81 |
82 | this.notifyDataSetChanged();
83 | }
84 |
85 | // ViewHolder support class
86 | class AppViewHolder {
87 | ImageView icon;
88 | TextView title ;
89 | TextView desc;
90 |
91 | AppViewHolder ( View v ) {
92 | icon = (ImageView) v.findViewById(R.id.rowIcon);
93 | title = (TextView) v.findViewById(R.id.rowTitle);
94 | desc = (TextView) v.findViewById(R.id.rowDesc);
95 | }
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
30 |
31 |
32 |
33 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
62 |
63 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/AppSettings.java:
--------------------------------------------------------------------------------
1 | package com.pcortex.pcgmclient;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.preference.PreferenceManager;
8 | import android.util.Log;
9 |
10 | /**
11 | * Created by fdam on 12-03-2015.
12 | */
13 | public class AppSettings {
14 | private static final String TAG = AppSettings.class.getSimpleName();
15 | private static final String PROPERTY_REG_ID = "registration_id";
16 | private static final String PROPERTY_APP_VERSION = "appVersion";
17 | private Context mContext;
18 |
19 | SharedPreferences prefs;
20 |
21 | public AppSettings ( Context context ) {
22 | mContext = context;
23 | prefs = PreferenceManager.getDefaultSharedPreferences(context);
24 | }
25 | /**
26 | * Gets the current registration ID for application on GCM service, if there is one.
27 | *
28 | * If result is empty, the app needs to register.
29 | *
30 | * @return registration ID, or empty string if there is no existing
31 | * registration ID.
32 | */
33 | public String getRegistrationId() {
34 |
35 | String registrationId = prefs.getString(PROPERTY_REG_ID, "");
36 | if (registrationId.isEmpty()) {
37 | Log.i(TAG, "Registration not found.");
38 | return "";
39 | }
40 | // Check if app was updated; if so, it must clear the registration ID
41 | // since the existing regID is not guaranteed to work with the new
42 | // app version.
43 | int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
44 | int currentVersion = getAppVersion();
45 | if (registeredVersion != currentVersion) {
46 | Log.i(TAG, "App version changed.");
47 | return "";
48 | }
49 | //Log.i( TAG , "Stored registration id: " + registrationId );
50 | return registrationId;
51 | }
52 |
53 | public String getGCMProjectId() {
54 |
55 | String projectId = prefs.getString("pref_gcmkey", "");
56 | if (projectId.isEmpty()) {
57 | Log.i(TAG, "GCM Project key not found/defined");
58 | return "";
59 | }
60 | //Log.i( TAG , "Project ID found: " + projectId );
61 | return projectId;
62 | }
63 |
64 | public String getDeviceId() {
65 |
66 | String deviceId = prefs.getString("pref_deviceid", "");
67 | if (deviceId.isEmpty()) {
68 | Log.i(TAG, "GCM Project key not found/defined");
69 | return "";
70 | }
71 | //Log.i( TAG , "Device ID found: " + deviceId );
72 | return deviceId;
73 | }
74 |
75 | public boolean getIsBackEndEnabled(Context context) {
76 | return prefs.getBoolean("pref_backendenabled" , false );
77 | }
78 |
79 | public void storeDeviceId( String devId) {
80 |
81 | SharedPreferences.Editor editor = prefs.edit();
82 | editor.putString("pref_deviceid", devId);
83 |
84 | editor.commit();
85 | }
86 | /**
87 | * Stores the registration ID and the app versionCode in the application's
88 | * {@code SharedPreferences}.
89 | *
90 | * @param regId registration ID
91 | */
92 | public void storeRegistrationId(String regId) {
93 |
94 | int appVersion = getAppVersion();
95 | Log.i(TAG, "Saving regId on app version " + appVersion);
96 | SharedPreferences.Editor editor = prefs.edit();
97 | editor.putString(PROPERTY_REG_ID, regId);
98 | editor.putInt(PROPERTY_APP_VERSION, appVersion);
99 | editor.commit();
100 | }
101 |
102 | public void clearRegistrationId() {
103 |
104 | int appVersion = getAppVersion();
105 | Log.i(TAG, "Saving regId on app version " + appVersion);
106 | SharedPreferences.Editor editor = prefs.edit();
107 | editor.putString(PROPERTY_REG_ID, "");
108 | editor.putInt(PROPERTY_APP_VERSION, appVersion);
109 | editor.commit();
110 | }
111 |
112 | /**
113 | * @return Application's version code from the {@code PackageManager}.
114 | */
115 | public int getAppVersion() {
116 | try {
117 | PackageInfo packageInfo = mContext.getPackageManager()
118 | .getPackageInfo(mContext.getPackageName(), 0);
119 | return packageInfo.versionCode;
120 | } catch (PackageManager.NameNotFoundException e) {
121 | // should never happen
122 | throw new RuntimeException("Could not get package name: " + e);
123 | }
124 | }
125 |
126 | public boolean getNotificationsEnabled() {
127 | return prefs.getBoolean("notifications_new_message" , false );
128 | }
129 |
130 | public boolean getVibrateEnabled () {
131 | return prefs.getBoolean("notifications_new_message_vibrate", false );
132 | }
133 |
134 | public String getNotificationSound () {
135 | return prefs.getString("notifications_new_message_ringtone" , "content://settings/system/notification_sound");
136 | }
137 |
138 | // /**
139 | // * @return Application's {@code SharedPreferences}.
140 | // */
141 | // private SharedPreferences getGcmPreferences(Context mContext) {
142 | // // This sample app persists the registration ID in shared preferences, but
143 | // // how you store the regID in your app is up to you.
144 | // return getSharedPreferences(MainActivity.class.getSimpleName(),
145 | // Context.MODE_PRIVATE);
146 | // }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/AppFunctions.java:
--------------------------------------------------------------------------------
1 | package com.pcortex.pcgmclient;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.AsyncTask;
6 | import android.support.v4.content.LocalBroadcastManager;
7 | import android.util.Log;
8 |
9 | import com.google.android.gms.common.ConnectionResult;
10 | import com.google.android.gms.common.GooglePlayServicesUtil;
11 | import com.google.android.gms.gcm.GoogleCloudMessaging;
12 |
13 | import java.io.IOException;
14 |
15 | /**
16 | * Created by fdam on 13-03-2015.
17 | */
18 | public class AppFunctions {
19 | private static final String LOG_TAG = AppFunctions.class.getSimpleName();
20 | private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
21 |
22 | private Context mContext;
23 | private String regId;
24 | private String mError;
25 | private AppSettings appSettings;
26 | private GoogleCloudMessaging gcm;
27 | private AppAdapter mAdapter;
28 |
29 | public AppFunctions( Context context , AppAdapter appAdapter ) {
30 | mContext = context;
31 | mAdapter = appAdapter;
32 | appSettings = new AppSettings( context );
33 | }
34 |
35 | public String getError() {
36 | return mError;
37 | }
38 | /**
39 | * Check the device to make sure it has the Google Play Services APK. If
40 | * it doesn't, display a dialog that allows users to download the APK from
41 | * the Google Play Store or enable it in the device's system settings.
42 | */
43 | public boolean checkPlayServices() {
44 | int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
45 |
46 | if (resultCode != ConnectionResult.SUCCESS) {
47 |
48 | if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
49 | mError = GooglePlayServicesUtil.getErrorString(resultCode); // .getErrorDialog(resultCode, activity, PLAY_SERVICES_RESOLUTION_REQUEST).show();
50 | Log.i ( LOG_TAG , " Google Play Error: " + mError );
51 | } else {
52 | Log.i(LOG_TAG, "This device is not supported.");
53 |
54 | }
55 | return false;
56 | }
57 |
58 | return true;
59 | }
60 |
61 | public boolean registerDevice() {
62 |
63 | // Check device for Play Services APK. If check succeeds, proceed with GCM registration.
64 | if (checkPlayServices()) {
65 | gcm = GoogleCloudMessaging.getInstance(mContext);
66 | regId = appSettings.getRegistrationId();
67 |
68 | // If the registration id is empty we have to register at the google servers.
69 | if (regId.isEmpty()) {
70 | registerInBackground();
71 | } else {
72 | // We have the registration ID, but we send it again to the backend.
73 | sendRegistrationIdToBackend();
74 | }
75 | return true;
76 | } else {
77 | Log.i(LOG_TAG, "No valid Google Play Services APK found.");
78 | }
79 | return false;
80 | }
81 |
82 | /**
83 | * Registers the application with GCM servers asynchronously.
84 | *
85 | * Stores the registration ID and the app versionCode in the application's
86 | * shared preferences.
87 | */
88 | public void registerInBackground() {
89 |
90 | new AsyncTask() {
91 | @Override
92 | protected String doInBackground(Void... params) {
93 | String msg = "";
94 |
95 | // First let's see if we have the Project ID to register.
96 | String GCMProjectId = appSettings.getGCMProjectId();
97 |
98 | if (!GCMProjectId.contentEquals("")) {
99 |
100 | try {
101 | if (gcm == null) {
102 | gcm = GoogleCloudMessaging.getInstance(mContext);
103 | }
104 | regId = gcm.register(GCMProjectId);
105 |
106 | Log.i(LOG_TAG, "Device registered, registration ID=" + regId);
107 | // You should send the registration ID to your server over HTTP, so it
108 | // can use GCM/HTTP or CCS to send messages to your app.
109 | sendRegistrationIdToBackend();
110 |
111 | appSettings.storeRegistrationId(regId);
112 | } catch (IOException ex) {
113 | msg = "Error :" + ex.getMessage();
114 | // If there is an error, don't just keep trying to register.
115 | // Require the user to click a button again, or perform
116 | // exponential back-off.
117 | }
118 | return msg;
119 | } else {
120 | Log.i(LOG_TAG , "No GCM Project ID defined...");
121 | return "";
122 | }
123 | }
124 |
125 | }.execute(null, null, null);
126 | }
127 |
128 |
129 | /**
130 | * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP or CCS to send
131 | * messages to your app. Not needed for this demo since the device sends upstream messages
132 | * to a server that echoes back the message using the 'from' address in the message.
133 | */
134 | public void sendRegistrationIdToBackend() {
135 | if ( appSettings.getIsBackEndEnabled(mContext)) {
136 | BackendTask beTsk = new BackendTask(mContext , mAdapter);
137 |
138 | beTsk.execute("Register");
139 | }
140 | }
141 |
142 | public boolean getServerData() {
143 | if ( appSettings.getIsBackEndEnabled(mContext)) {
144 |
145 | BackendTask beTsk = new BackendTask(mContext , mAdapter);
146 |
147 | beTsk.execute("Ping");
148 |
149 | return true;
150 | } else {
151 | return false;
152 |
153 | }
154 |
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/MainActivity.java:
--------------------------------------------------------------------------------
1 | // Application icons are from www.icons4android.com
2 |
3 | package com.pcortex.pcgmclient;
4 |
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.content.res.Resources;
10 | import android.support.v4.content.LocalBroadcastManager;
11 | import android.support.v7.app.ActionBarActivity;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 | import android.view.Menu;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.widget.ListView;
18 |
19 | import java.util.UUID;
20 |
21 |
22 | public class MainActivity extends ActionBarActivity {
23 | private static final String LOG_TAG = MainActivity.class.getSimpleName();
24 |
25 | Context mContext;
26 | AppFunctions appFunctions ;
27 | AppSettings appSettings;
28 |
29 | ListView list;
30 | AppAdapter mAdapter;
31 | String[] msgTitles;
32 | String[] msgDescriptions;
33 | Integer[] images = {R.drawable.ic_info , R.drawable.ic_info};
34 |
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | Log.i(LOG_TAG , "Starting App: onCreate...");
39 |
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_main);
42 |
43 | mContext = getApplicationContext();
44 |
45 | // Let's fill the view with initial Data...
46 | Resources res = getResources();
47 | msgTitles = res.getStringArray(R.array.titles);
48 | msgDescriptions = res.getStringArray(R.array.descriptions);
49 |
50 | list = (ListView) findViewById(R.id.listView);
51 | // Our custom adapter that is associated to our ListView UI Object.
52 | mAdapter = new AppAdapter(mContext , images , msgTitles, msgDescriptions);
53 | list.setAdapter(mAdapter);
54 |
55 | appFunctions = new AppFunctions(mContext , mAdapter);
56 | appSettings = new AppSettings(mContext);
57 |
58 | // For updating the UI from data that is "published" from background services
59 | LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
60 | new IntentFilter("PC_GCM_NOTIFICATION"));
61 |
62 | // Let's get or generate a device id.
63 | String deviceId = appSettings.getDeviceId();
64 | if ( deviceId.contentEquals("") ) {
65 | deviceId = UUID.randomUUID().toString();
66 | appSettings.storeDeviceId(deviceId);
67 | Log.i(LOG_TAG, "Device id generated: " + deviceId);
68 | } else {
69 | Log.i(LOG_TAG, "Device id found: " + deviceId );
70 | }
71 |
72 | // Let's register this device in GCM servers.
73 | // This will also call our backend server if enabled.
74 | if (!appFunctions.registerDevice() )
75 | mAdapter.add( R.drawable.ic_error,"GCM Error", appFunctions.getError());
76 |
77 | }
78 |
79 | @Override
80 | protected void onPause() {
81 |
82 | LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
83 | super.onPause();
84 | }
85 |
86 | // This gets called when other activities or BroadcastReceivers want to update the UI.
87 | // Its main purpose is to update the UI from data received from the GCM notification
88 | // that comes from the GcmIntentService.
89 | private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
90 | @Override
91 | public void onReceive(Context context, Intent intent) {
92 | // Get extra data included in the Intent
93 | String title = intent.getStringExtra("title");
94 | String desc = intent.getStringExtra("desc");
95 | String msgType = intent.getStringExtra("type");
96 | int iconId = R.drawable.ic_error;
97 |
98 | if ( msgType.contentEquals("info")) iconId = R.drawable.ic_info;
99 | if ( msgType.contentEquals("unknown")) iconId = R.drawable.ic_action;
100 |
101 | mAdapter.add( iconId , title , desc ); // Add to the adapter that will refresh the list view UI.
102 |
103 | }
104 | };
105 |
106 | @Override
107 | public boolean onCreateOptionsMenu(Menu menu) {
108 | // Inflate the menu; this adds items to the action bar if it is present.
109 | getMenuInflater().inflate(R.menu.menu_main, menu);
110 | return true;
111 | }
112 |
113 | @Override
114 | public boolean onOptionsItemSelected(MenuItem item) {
115 | // Handle action bar item clicks here. The action bar will
116 | // automatically handle clicks on the Home/Up button, so long
117 | // as you specify a parent activity in AndroidManifest.xml.
118 | int id = item.getItemId();
119 |
120 | if (id == R.id.action_settings) {
121 | startActivity(new Intent(this , SettingsActivity.class));
122 | return true;
123 | }
124 |
125 | return super.onOptionsItemSelected(item);
126 | }
127 |
128 | @Override
129 | protected void onResume() {
130 | super.onResume();
131 | // Check device for Play Services APK.
132 | appFunctions.checkPlayServices();
133 | }
134 |
135 | @Override
136 | protected void onDestroy() {
137 |
138 | super.onDestroy();
139 | }
140 |
141 |
142 | // Send an upstream message.
143 | public void onClick(final View view) {
144 |
145 | if ( view == findViewById(R.id.send)) {
146 | Boolean status = appFunctions.getServerData(); // Just for fun. Get server data.
147 | if ( status )
148 | mAdapter.add( R.drawable.ic_info , "Backend Request", "Getting data...");
149 | else
150 | mAdapter.add( R.drawable.ic_error, "Backend Request", "Server is disabled in settings");
151 |
152 | }
153 | if ( view == findViewById(R.id.clear)) {
154 | mAdapter.clear();
155 | }
156 |
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/GcmNotificationIntentService.java:
--------------------------------------------------------------------------------
1 | package com.pcortex.pcgmclient;
2 |
3 | import android.app.IntentService;
4 | import android.app.NotificationManager;
5 | import android.app.PendingIntent;
6 | import android.content.Intent;
7 | import android.content.Context;
8 | import android.graphics.Color;
9 | import android.net.Uri;
10 | import android.os.Bundle;
11 | import android.os.Handler;
12 | import android.support.v4.app.NotificationCompat;
13 | import android.support.v4.content.LocalBroadcastManager;
14 | import android.util.Log;
15 | import android.widget.Toast;
16 |
17 | import com.google.android.gms.gcm.GoogleCloudMessaging;
18 |
19 | import java.util.Iterator;
20 | import java.util.Set;
21 |
22 |
23 | /**
24 | * An {@link IntentService} subclass for handling asynchronous task requests in
25 | * a service on a separate handler thread.
26 | *
27 | * TODO: Customize class - update intent actions, extra parameters and static
28 | * helper methods.
29 | */
30 | public class GcmNotificationIntentService extends IntentService {
31 | static final String TAG = GcmNotificationIntentService.class.getSimpleName();
32 |
33 | static final int NOTIFICATION_ID = 1;
34 | NotificationManager mNotificationManager;
35 |
36 | Context mContext;
37 | Handler mHandler;
38 |
39 | public GcmNotificationIntentService() {
40 |
41 | super("GcmNotificationIntentService");
42 | mHandler = new Handler();
43 | }
44 |
45 | @Override
46 | protected void onHandleIntent(Intent intent) {
47 |
48 | if (intent != null) {
49 | final String action = intent.getAction();
50 | Bundle extras = intent.getExtras();
51 | GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
52 |
53 | Log.d(TAG, "Entered Intent Service function...");
54 |
55 | String messageType = gcm.getMessageType(intent);
56 |
57 | if (!extras.isEmpty()) { // has effect of unparcelling Bundle
58 | /*
59 | * Filter messages based on message type. Since it is likely that GCM will be
60 | * extended in the future with new message types, just ignore any message types you're
61 | * not interested in, or that you don't recognize.
62 | */
63 | if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
64 | sendNotification("Send error: " , extras.toString());
65 | } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
66 | sendNotification("Deleted messages on server: " , extras.toString());
67 | // If it's a regular GCM message, do some work.
68 | } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
69 | Log.d(TAG, "Received: " + extras.toString());
70 |
71 | // Get intent notification data:
72 | String title = getNotificationTitle( intent );
73 | String desc = getNotificationDesc ( intent );
74 |
75 | // Post notification of received message.
76 | sendNotification(title , desc );
77 |
78 | // Update user interface to show the new arrived GCM notification
79 | updateUI(title , desc);
80 |
81 | dumpIntent(intent); // For debug purposes. Use adb logcat or Android Studio to view contents.
82 | }
83 | }
84 | // Release the wake lock provided by the WakefulBroadcastReceiver.
85 | GcmBroadcastReceiver.completeWakefulIntent(intent);
86 |
87 | }
88 | }
89 |
90 | // Put the message into a notification and post it.
91 | // This is just one simple example of what you might choose to do with
92 | // a GCM message.
93 | private void sendNotification(String title , String desc ) {
94 | AppSettings appSettings = new AppSettings(getApplicationContext());
95 | mNotificationManager = (NotificationManager)
96 | this.getSystemService(Context.NOTIFICATION_SERVICE);
97 |
98 | // This is the Intent that calls MainActivity when the notification is pressed.
99 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
100 | new Intent(this, MainActivity.class), 0);
101 |
102 | NotificationCompat.Builder mBuilder =
103 | new NotificationCompat.Builder(this)
104 | .setSmallIcon(R.drawable.ic_stat_gcm)
105 | .setContentTitle(title)
106 | .setStyle(new NotificationCompat.BigTextStyle()
107 | .bigText(title))
108 | .setContentText(desc);
109 |
110 | if ( appSettings.getNotificationsEnabled() ) {
111 | mBuilder.setLights(Color.BLUE, 500, 500);
112 | mBuilder.setContentIntent(contentIntent);
113 | mBuilder.setStyle(new NotificationCompat.InboxStyle());
114 | mBuilder.setSound(Uri.parse(appSettings.getNotificationSound()));
115 |
116 | if ( appSettings.getVibrateEnabled()) {
117 | long[] pattern = {500, 500, 500, 500};
118 | mBuilder.setVibrate(pattern);
119 | }
120 |
121 |
122 | }
123 | mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
124 | }
125 |
126 | private void updateUI( String title , String desc ) {
127 | final String mTitle = title;
128 | final String mDesc = desc ;
129 |
130 | mContext = getApplicationContext();
131 |
132 | mHandler.post( new Runnable() {
133 | @Override
134 | public void run() {
135 | //Toast.makeText(mContext,"Notification received",Toast.LENGTH_LONG).show();
136 |
137 | //Log.d("sender", "Broadcasting message");
138 | Intent intent = new Intent("PC_GCM_NOTIFICATION");
139 | // You can also include some extra data.
140 | intent.putExtra("type" , "info");
141 | intent.putExtra("title" , mTitle);
142 | intent.putExtra("desc" , mDesc );
143 | LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
144 |
145 | }
146 | });
147 |
148 | }
149 |
150 | private static void dumpIntent(Intent i){
151 |
152 | Bundle bundle = i.getExtras();
153 | if (bundle != null) {
154 | Set keys = bundle.keySet();
155 | Iterator it = keys.iterator();
156 | Log.d(TAG,"Dumping Intent start");
157 | while (it.hasNext()) {
158 | String key = it.next();
159 | Log.d(TAG,"[" + key + "=" + bundle.get(key)+"]");
160 | }
161 | Log.d(TAG,"Dumping Intent end");
162 | }
163 | }
164 |
165 | private String notificationToString( Intent i ) {
166 | Bundle bundle = i.getExtras();
167 | String message = "" ;
168 |
169 | if ( bundle != null) {
170 | Set keys = bundle.keySet();
171 | Iterator it = keys.iterator();
172 |
173 | while (it.hasNext()) {
174 | String key = it.next();
175 | message = message + "[" + key + "=" + bundle.get(key)+"]\n";
176 | }
177 | }
178 |
179 | return message;
180 | }
181 |
182 | private String getNotificationTitle ( Intent i ) {
183 | Bundle bundle = i.getExtras();
184 | String title = "GCM Notification";
185 |
186 | if (bundle != null) {
187 | title = bundle.getString("title");
188 | if ( title == null )
189 | title = "GCM Notification";
190 | }
191 |
192 | return title;
193 | }
194 |
195 | private String getNotificationDesc ( Intent i ) {
196 | Bundle bundle = i.getExtras();
197 | String title = "Received notification from GCM servers";
198 |
199 | if (bundle != null) {
200 | title = bundle.getString("desc");
201 | if ( title == null )
202 | title = "Received notification from GCM servers";
203 | }
204 |
205 | return title;
206 | }
207 |
208 |
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/BackendTask.java:
--------------------------------------------------------------------------------
1 | package com.pcortex.pcgmclient;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.AsyncTask;
7 | import android.preference.PreferenceManager;
8 | import android.support.v4.content.LocalBroadcastManager;
9 | import android.util.Log;
10 |
11 | import org.apache.http.HttpResponse;
12 | import org.apache.http.HttpStatus;
13 | import org.apache.http.StatusLine;
14 | import org.apache.http.client.HttpClient;
15 | import org.apache.http.client.entity.UrlEncodedFormEntity;
16 | import org.apache.http.client.methods.HttpPost;
17 | import org.apache.http.entity.StringEntity;
18 | import org.apache.http.impl.client.DefaultHttpClient;
19 | import org.apache.http.message.BasicHeader;
20 | import org.apache.http.message.BasicNameValuePair;
21 | import org.apache.http.protocol.HTTP;
22 | import org.json.JSONObject;
23 |
24 | import java.io.BufferedReader;
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.io.InputStreamReader;
28 | import java.io.UnsupportedEncodingException;
29 | import java.util.ArrayList;
30 | import java.util.HashMap;
31 | import java.util.Iterator;
32 | import java.util.List;
33 | import java.util.Map;
34 |
35 | /**
36 | * Created by fdam on 10-03-2015.
37 | */
38 | public class BackendTask extends AsyncTask {
39 | private final String LOG_TAG = BackendTask.class.getSimpleName();
40 |
41 | private Context mContext;
42 |
43 | private String deviceId;
44 | private String registrationId;
45 |
46 | private AppAdapter mAdapter;
47 | private int mIcon;
48 | private String mTitle;
49 | private String mDesc;
50 |
51 | private Map serverResponse;
52 |
53 | public BackendTask ( Context context , AppAdapter appAdapter) {
54 | mContext = context;
55 | mAdapter = appAdapter;
56 | // To hold up Json key/values response from server.
57 | serverResponse = new HashMap();
58 | }
59 |
60 | @Override
61 | protected void onPreExecute() {
62 | super.onPreExecute();
63 | //Log.i(LOG_TAG, "onPreExecute");
64 |
65 | AppSettings appSettings = new AppSettings(mContext);
66 |
67 | deviceId = appSettings.getDeviceId();
68 | registrationId = appSettings.getRegistrationId();
69 |
70 | }
71 |
72 | @Override
73 | protected Void doInBackground(String... params) {
74 | JSONObject message = new JSONObject();
75 |
76 | String baseURL = getBackEndURL();
77 | String operation = params[0];
78 |
79 | Boolean isDone = false;
80 | StatusLine statusLine;
81 | int statusCode;
82 | String result ="";
83 | String strMsg ="";
84 |
85 | try {
86 | message.put("Operation", operation);
87 | message.put("DeviceId" , deviceId);
88 | if ( operation.contentEquals("Register") || operation.contentEquals("ReRegister")) {
89 | message.put("RegistrationID", registrationId);
90 | }
91 | } catch ( Exception e) {
92 | e.printStackTrace();
93 | }
94 |
95 | Log.i ( LOG_TAG , "Json request: " + message.toString() );
96 |
97 | try {
98 | HttpClient httpClient = new DefaultHttpClient();
99 |
100 | HttpPost httpPost = new HttpPost(baseURL);
101 |
102 | // BasicNameValuePair param = new BasicNameValuePair("message", message.toString() );
103 | // List paramslist = new ArrayList();
104 | //
105 | // paramslist.add(param);
106 | //
107 | // UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramslist);
108 | // entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
109 | //entity.setContentEncoding(HTTP.ISO_8859_1);
110 |
111 | StringEntity entity = new StringEntity( message.toString());
112 |
113 |
114 | httpPost.setEntity(entity);
115 | httpPost.setHeader("User-Agent", "AndroidPGCM/1.0");
116 | httpPost.setHeader("Accept", "application/json");
117 | httpPost.setHeader("Content-type", "application/json");
118 |
119 | //Execute the request
120 |
121 | HttpResponse httpResponse = httpClient.execute(httpPost);
122 |
123 | statusLine = httpResponse.getStatusLine();
124 | statusCode = statusLine.getStatusCode();
125 |
126 | InputStream inputStream = httpResponse.getEntity().getContent();
127 |
128 | Log.i(LOG_TAG , "HTTP Response Code: " + Integer.toString(statusCode));
129 |
130 | if(inputStream != null){
131 | switch ( statusCode) {
132 | case HttpStatus.SC_OK:
133 | result = getStringFromInputStream(inputStream);
134 | Log.i(LOG_TAG, "Backend Server response: " + result);
135 | isDone = true;
136 | strMsg = "Data received ok.";
137 | break;
138 | case HttpStatus.SC_BAD_GATEWAY:
139 | strMsg = "Unable to connect.";
140 |
141 | break;
142 | case HttpStatus.SC_INTERNAL_SERVER_ERROR:
143 | strMsg = "Remote Internal Server Error.";
144 | break;
145 | default:
146 | strMsg = "Something failed! Code: " + Integer.toString(statusCode);
147 | break;
148 | }
149 | }
150 | else{
151 | strMsg = "Failed to get result...";
152 | }
153 |
154 | } catch (UnsupportedEncodingException uex ) {
155 | uex.printStackTrace();
156 | } catch (Exception e) {
157 | e.printStackTrace();
158 | }
159 |
160 | // Process the JSon response.
161 | if ( isDone ) {
162 | // Returns true if the response is valid JSON
163 | boolean success = decodeResponse(result);
164 |
165 | mIcon = R.drawable.ic_info;
166 | if ( success ) {
167 | String rCode = serverResponse.get("rcode");
168 |
169 |
170 | mTitle = serverResponse.get("title");
171 | mDesc = serverResponse.get("desc");
172 |
173 | if ( (rCode == null) || (mTitle == null) || (mDesc==null) ) {
174 | mTitle = "Backend Server Response";
175 | mDesc = "Response OK, but not decoded.";
176 |
177 | }
178 | } else {
179 | mIcon = R.drawable.ic_error;
180 | mTitle = "BackEnd Server Response";
181 | mDesc = "Got no valid JSON answer.";
182 | }
183 |
184 | } else {
185 | // You can also include some extra data.
186 | mIcon = R.drawable.ic_error;
187 | mTitle = "Error on BackEnd Server";
188 | mDesc = "Error connecting to Back End Server " + strMsg ;
189 | }
190 |
191 | return null;
192 | }
193 |
194 | @Override
195 | protected void onPostExecute(Void aVoid) {
196 | super.onPostExecute(aVoid);
197 |
198 | // Update the UI
199 | mAdapter.add( mIcon , mTitle , mDesc);
200 |
201 | }
202 |
203 | private String getBackEndURL() {
204 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext.getApplicationContext());
205 | String server = prefs.getString("pref_server", "" );
206 | String port = prefs.getString("pref_port", "");
207 | String baseURL= prefs.getString("pref_baseurl", "");
208 |
209 | String URL = "http://" + server;
210 |
211 | if ( !port.contentEquals(""))
212 | URL = URL + ":" + port;
213 |
214 | URL = URL + baseURL;
215 |
216 | Log.i (LOG_TAG , "Backend URL: " + URL);
217 |
218 | return URL;
219 |
220 | }
221 |
222 | // convert InputStream to String
223 | private static String getStringFromInputStream(InputStream is) {
224 |
225 | BufferedReader br = null;
226 | StringBuilder sb = new StringBuilder();
227 |
228 | String line;
229 | try {
230 |
231 | br = new BufferedReader(new InputStreamReader(is));
232 | while ((line = br.readLine()) != null) {
233 | sb.append(line);
234 | }
235 |
236 | } catch (IOException e) {
237 | e.printStackTrace();
238 | } finally {
239 | if (br != null) {
240 | try {
241 | br.close();
242 | } catch (IOException e) {
243 | e.printStackTrace();
244 | }
245 | }
246 | }
247 |
248 | return sb.toString();
249 |
250 | }
251 |
252 | /*
253 | * Convert the HTTP Response to a Json object and from there fill up the class variables
254 | */
255 | private boolean decodeResponse(String json) {
256 | JSONObject msg;
257 |
258 | try {
259 | msg = new JSONObject( json );
260 |
261 | Iterator iter = msg.keys();
262 | while ( iter.hasNext() ) {
263 | String key = (String)iter.next();
264 | String value = msg.getString(key);
265 | serverResponse.put( key , value );
266 | }
267 |
268 | } catch ( Exception e ) {
269 | Log.i(LOG_TAG , "Http response to Json failed: " + e.toString());
270 | return false;
271 |
272 | }
273 |
274 | return true;
275 |
276 | }
277 |
278 | }
279 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pcortex/pcgmclient/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.pcortex.pcgmclient;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.Configuration;
6 | import android.media.Ringtone;
7 | import android.media.RingtoneManager;
8 | import android.net.Uri;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.preference.ListPreference;
12 | import android.preference.Preference;
13 | import android.preference.PreferenceActivity;
14 | import android.preference.PreferenceCategory;
15 | import android.preference.PreferenceFragment;
16 | import android.preference.PreferenceManager;
17 | import android.preference.RingtonePreference;
18 | import android.text.TextUtils;
19 |
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * A {@link PreferenceActivity} that presents a set of application settings. On
25 | * handset devices, settings are presented as a single list. On tablets,
26 | * settings are split by category, with category headers shown to the left of
27 | * the list of settings.
28 | *
29 | * See
30 | * Android Design: Settings for design guidelines and the Settings
32 | * API Guide for more information on developing a Settings UI.
33 | */
34 | public class SettingsActivity extends PreferenceActivity {
35 | /**
36 | * Determines whether to always show the simplified settings UI, where
37 | * settings are presented in a single list. When false, settings are shown
38 | * as a master/detail two-pane view on tablets. When true, a single pane is
39 | * shown on tablets.
40 | */
41 | private static final boolean ALWAYS_SIMPLE_PREFS = false;
42 |
43 |
44 | @Override
45 | protected void onPostCreate(Bundle savedInstanceState) {
46 | super.onPostCreate(savedInstanceState);
47 |
48 | setupSimplePreferencesScreen();
49 | }
50 |
51 | /**
52 | * Shows the simplified settings UI if the device configuration if the
53 | * device configuration dictates that a simplified, single-pane UI should be
54 | * shown.
55 | */
56 | private void setupSimplePreferencesScreen() {
57 | if (!isSimplePreferences(this)) {
58 | return;
59 | }
60 |
61 | // In the simplified UI, fragments are not used at all and we instead
62 | // use the older PreferenceActivity APIs.
63 |
64 | // Add 'general' preferences.
65 |
66 | addPreferencesFromResource(R.xml.pref_general);
67 |
68 | // Add 'notifications' preferences, and a corresponding header.
69 | PreferenceCategory fakeHeader = new PreferenceCategory(this);
70 | fakeHeader.setTitle(R.string.pref_header_notifications);
71 | getPreferenceScreen().addPreference(fakeHeader);
72 | addPreferencesFromResource(R.xml.pref_notification);
73 |
74 | // Add 'data and sync' preferences, and a corresponding header.
75 | //fakeHeader = new PreferenceCategory(this);
76 | //fakeHeader.setTitle(R.string.pref_header_data_sync);
77 | //getPreferenceScreen().addPreference(fakeHeader);
78 | //addPreferencesFromResource(R.xml.pref_data_sync);
79 |
80 | // Bind the summaries of EditText/List/Dialog/Ringtone preferences to
81 | // their values. When their values change, their summaries are updated
82 | // to reflect the new value, per the Android Design guidelines.
83 | bindPreferenceSummaryToValue(findPreference("pref_server"));
84 | bindPreferenceSummaryToValue(findPreference("pref_port"));
85 | bindPreferenceSummaryToValue(findPreference("pref_baseurl"));
86 | bindPreferenceSummaryToValue(findPreference("pref_gcmkey"));
87 | bindPreferenceSummaryToValue(findPreference("pref_deviceid"));
88 | //bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
89 | //bindPreferenceSummaryToValue(findPreference("sync_frequency"));
90 | }
91 |
92 | /**
93 | * {@inheritDoc}
94 | */
95 | @Override
96 | public boolean onIsMultiPane() {
97 | return isXLargeTablet(this) && !isSimplePreferences(this);
98 | }
99 |
100 | /**
101 | * Helper method to determine if the device has an extra-large screen. For
102 | * example, 10" tablets are extra-large.
103 | */
104 | private static boolean isXLargeTablet(Context context) {
105 | return (context.getResources().getConfiguration().screenLayout
106 | & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
107 | }
108 |
109 | /**
110 | * Determines whether the simplified settings UI should be shown. This is
111 | * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
112 | * doesn't have newer APIs like {@link PreferenceFragment}, or the device
113 | * doesn't have an extra-large screen. In these cases, a single-pane
114 | * "simplified" settings UI should be shown.
115 | */
116 | private static boolean isSimplePreferences(Context context) {
117 | return ALWAYS_SIMPLE_PREFS
118 | || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
119 | || !isXLargeTablet(context);
120 | }
121 |
122 | /**
123 | * {@inheritDoc}
124 | */
125 | @Override
126 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
127 | public void onBuildHeaders(List target) {
128 | if (!isSimplePreferences(this)) {
129 | loadHeadersFromResource(R.xml.pref_headers, target);
130 | }
131 | }
132 |
133 | /**
134 | * A preference value change listener that updates the preference's summary
135 | * to reflect its new value.
136 | */
137 | private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
138 | @Override
139 | public boolean onPreferenceChange(Preference preference, Object value) {
140 | String stringValue = value.toString();
141 |
142 | if (preference instanceof ListPreference) {
143 | // For list preferences, look up the correct display value in
144 | // the preference's 'entries' list.
145 | ListPreference listPreference = (ListPreference) preference;
146 | int index = listPreference.findIndexOfValue(stringValue);
147 |
148 | // Set the summary to reflect the new value.
149 | preference.setSummary(
150 | index >= 0
151 | ? listPreference.getEntries()[index]
152 | : null);
153 |
154 | } else if (preference instanceof RingtonePreference) {
155 | // For ringtone preferences, look up the correct display value
156 | // using RingtoneManager.
157 | if (TextUtils.isEmpty(stringValue)) {
158 | // Empty values correspond to 'silent' (no ringtone).
159 | preference.setSummary(R.string.pref_ringtone_silent);
160 |
161 | } else {
162 | Ringtone ringtone = RingtoneManager.getRingtone(
163 | preference.getContext(), Uri.parse(stringValue));
164 |
165 | if (ringtone == null) {
166 | // Clear the summary if there was a lookup error.
167 | preference.setSummary(null);
168 | } else {
169 | // Set the summary to reflect the new ringtone display
170 | // name.
171 | String name = ringtone.getTitle(preference.getContext());
172 | preference.setSummary(name);
173 | }
174 | }
175 |
176 | } else {
177 | // For all other preferences, set the summary to the value's
178 | // simple string representation.
179 | preference.setSummary(stringValue);
180 | }
181 | return true;
182 | }
183 | };
184 |
185 | /**
186 | * Binds a preference's summary to its value. More specifically, when the
187 | * preference's value is changed, its summary (line of text below the
188 | * preference title) is updated to reflect the value. The summary is also
189 | * immediately updated upon calling this method. The exact display format is
190 | * dependent on the type of preference.
191 | *
192 | * @see #sBindPreferenceSummaryToValueListener
193 | */
194 | private static void bindPreferenceSummaryToValue(Preference preference) {
195 | // Set the listener to watch for value changes.
196 | preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
197 |
198 | // Trigger the listener immediately with the preference's
199 | // current value.
200 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
201 | PreferenceManager
202 | .getDefaultSharedPreferences(preference.getContext())
203 | .getString(preference.getKey(), ""));
204 | }
205 |
206 | /**
207 | * This fragment shows general preferences only. It is used when the
208 | * activity is showing a two-pane settings UI.
209 | */
210 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
211 | public static class GeneralPreferenceFragment extends PreferenceFragment {
212 | @Override
213 | public void onCreate(Bundle savedInstanceState) {
214 | super.onCreate(savedInstanceState);
215 | addPreferencesFromResource(R.xml.pref_general);
216 |
217 | // Bind the summaries of EditText/List/Dialog/Ringtone preferences
218 | // to their values. When their values change, their summaries are
219 | // updated to reflect the new value, per the Android Design
220 | // guidelines.
221 | bindPreferenceSummaryToValue(findPreference("pref_server"));
222 | bindPreferenceSummaryToValue(findPreference("pref_port"));
223 | bindPreferenceSummaryToValue(findPreference("pref_baseurl"));
224 | bindPreferenceSummaryToValue(findPreference("pref_gcmkey"));
225 | }
226 | }
227 |
228 | /**
229 | * This fragment shows notification preferences only. It is used when the
230 | * activity is showing a two-pane settings UI.
231 | */
232 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
233 | public static class NotificationPreferenceFragment extends PreferenceFragment {
234 | @Override
235 | public void onCreate(Bundle savedInstanceState) {
236 | super.onCreate(savedInstanceState);
237 | addPreferencesFromResource(R.xml.pref_notification);
238 |
239 | // Bind the summaries of EditText/List/Dialog/Ringtone preferences
240 | // to their values. When their values change, their summaries are
241 | // updated to reflect the new value, per the Android Design
242 | // guidelines.
243 | bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
244 | }
245 | }
246 |
247 | /**
248 | * This fragment shows data and sync preferences only. It is used when the
249 | * activity is showing a two-pane settings UI.
250 | */
251 | // @TargetApi(Build.VERSION_CODES.HONEYCOMB)
252 | // public static class DataSyncPreferenceFragment extends PreferenceFragment {
253 | // @Override
254 | // public void onCreate(Bundle savedInstanceState) {
255 | // super.onCreate(savedInstanceState);
256 | // addPreferencesFromResource(R.xml.pref_data_sync);
257 | //
258 | // // Bind the summaries of EditText/List/Dialog/Ringtone preferences
259 | // // to their values. When their values change, their summaries are
260 | // // updated to reflect the new value, per the Android Design
261 | // // guidelines.
262 | // bindPreferenceSummaryToValue(findPreference("sync_frequency"));
263 | // }
264 | // }
265 | }
266 |
--------------------------------------------------------------------------------
/app/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
272 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 | localhost
345 | 5050
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 | 1427044323015
356 | 1427044323015
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
395 |
398 |
399 |
400 |
401 |
402 |
403 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
--------------------------------------------------------------------------------