Android not restoring instance state - android

I know similar questions have been asked but none of the solutions to those questions have been working for me.
When I go ahead and try to save the state of my app, the state of the EditText views are not being saved and restored. I went ahead and commented everything out and just put in a temporary string to save but when the app loads up again, the onCreate() method does not print 'Restoring instance state'
package com.fwumdesoft.udppacketsender;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/**
* Posts a UDP message with the given data to the
* target address on the target port.
*/
class UdpPostActivity extends AppCompatActivity {
private static final String TAG = "UdpPostActivity";
private static final String stateTextTargetHost = "com.fwumdesoft#TargetHost";
private static final String stateTextTargetPort = "com.fwumdesoft#TargetPort";
private static final String stateTextHexData = "com.fwumdesoft#HexData";
private static final String stateTextStringData = "com.fwumdesoft#StringData";
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.v(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_udp_post);
if (savedInstanceState != null) {
// ((EditText) findViewById(R.id.txtAddress)).setText(savedInstanceState.getString(stateTextTargetHost));
// ((EditText) findViewById(R.id.txtPort)).setText(savedInstanceState.getString(stateTextTargetPort));
// ((EditText) findViewById(R.id.txtData)).setText(savedInstanceState.getString(stateTextHexData));
// ((EditText) findViewById(R.id.txtStringData)).setText(savedInstanceState.getString(stateTextStringData));
String text = savedInstanceState.getString(stateTextStringData);
Log.v(TAG, "Restoring instance state");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// outState.putString(stateTextTargetHost, ((EditText)findViewById(R.id.txtAddress)).getText().toString());
// outState.putString(stateTextTargetPort, ((EditText)findViewById(R.id.txtPort)).getText().toString());
// outState.putString(stateTextHexData, ((EditText)findViewById(R.id.txtData)).getText().toString());
// outState.putString(stateTextStringData, ((EditText)findViewById(R.id.txtStringData)).getText().toString());
super.onSaveInstanceState(outState);
outState.putString(stateTextStringData, "test");
Log.v(TAG, "Saved instance state");
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.v(TAG, "onRestore");
// ((EditText)findViewById(R.id.txtAddress)).setText(savedInstanceState.getString(stateTextTargetHost));
// ((EditText)findViewById(R.id.txtPort)).setText(savedInstanceState.getString(stateTextTargetPort));
// ((EditText)findViewById(R.id.txtData)).setText(savedInstanceState.getString(stateTextHexData));
// ((EditText)findViewById(R.id.txtStringData)).setText(savedInstanceState.getString(stateTextStringData));
}
In the logcat output I get "Saved instance state" and then "onCreate" but I do not get "Restoring instance state" or "onRestore" when restarting the app.

Go to debug mode and see if your onCreate is being called. Do you have android:configChanges set in your manifest?

You should refer to the key you gave in outState when checking if savedInstanceState is not null, like this.
if (savedInstanceState != null) {
String text = savedInstanceState.getString("test");
Log.v(TAG, "Restoring instance state");
}
This documentation may shed some light
https://developer.android.com/guide/components/activities/activity-lifecycle.html

Related

Access defaultSharedPreferences in class from service

Long story short, I have a class that handles my app shared preferences.
I call it from various other classes without issues, but when I try to call it from my service (from the same APK) I get a null exception. I am guessing that it's getting called from the wrong context or something like that. Here is the relevant code.
MainActivity.java
package com.deskwizard.audiomanager;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.deskwizard.audiomanager.DataSaveRestore;
public class MainActivity extends FragmentActivity {
public static Context contextOfApplication;
final FragmentManager fm = getFragmentManager();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contextOfApplication = getApplicationContext();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_settings, new FadeBalanceFragment());
ft.commit();
// TODO: Load previously saved settings for all values
DataSaveRestore.restore_all();
// TODO: init I2C
}
public static Context getContextOfApplication() {
return contextOfApplication;
}
}
DataSaveRestore.java (defaultpreferences class)
package com.deskwizard.audiomanager;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
public class DataSaveRestore extends Application {
// Data variables
public static int Bass_level, Bass_CFreq, Bass_Qfact, Sub_level,
Sub_Lowpass, Treble_level, Treble_CFreq, Mid_level, Mid_CFreq,
Mid_Qfact, Fade, Balance, Loudness_level, Loudness_freq,
Loudness_boost;
static boolean Bass_DCMode, Loudness_state;
static Context applicationContext = MainActivity.getContextOfApplication();
public static void restore_all() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(applicationContext);
if (prefs.getInt("data_saved", 0) == 0) {
set_defaults();
load_defaults();
} else {
load_defaults();
}
//TODO: send settings to TDA7418
DS3903.set_lowpass(DataSaveRestore.Sub_Lowpass);
};
Service code snippet:
public class AudioManagerService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO do something useful
Log.d("com.deskwizard.audiomanager", "starting service...");
DataSaveRestore.restore_all(); // restore settings to TDA7418/DS3903
start();
return Service.START_STICKY;
}
The Null Exception error refers to this line, only when called from the service, it works properly from the main application and other classes:
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(applicationContext);
Let me know if any further code can help narrow it down.
Thanks,
DW
Because, In your service when you call, DataSaveRestore.restore_all(); It make reference on, (As there is no MainActivity context available from Servce)
static Context applicationContext = MainActivity.getContextOfApplication();
on this line, applicationContext will be null as it can't find MainActivity initialization
Simply, Just change your restore_all() method from Application class.
First remove static and and use getApplicationContext() of Android application class method to get application context as in Service,
public void restore_all() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getInt("data_saved", 0) == 0) {
set_defaults();
load_defaults();
} else {
load_defaults();
}
//TODO: send settings to TDA7418
DS3903.set_lowpass(DataSaveRestore.Sub_Lowpass);
};
Now call, restore_all(); by initializing object of Application class not a static way.
Like,
DataSaveRestore dataSaveRestore = (DataSaveRestore) getApplicationContext();
dataSaveRestore.restore_all();

AsyncTask *occasionally* getting stuck with connection timeout/error problems, potential memory leak or Android Studio bug?

I'm new at Android and Java development I've put together a simple demo app to start learning. It is made of:
a main activity extending ActionBarActivity, in which
a ViewPager is instantiated which has
a FragmentPagerAdapter responsible for showing up...
...one Fragment out of three at a given time and
one of those fragments, when it is created, just to try things out, executes an AsyncTask (defined by another class) which triggers an HTTP request that when done (onPostExecute)...
populates a TableLayout in the Fragment that fired it.
I'm also trying to keep compatibility with older Android platforms, so I'm using support library where necessary.
The problem that I am seeing, or I should say that I was seeing (keep reading..), is that from time to time I get
org.apache.http.conn.HttpHostConnectException: Connection to http://123.123.123.123:80/notes.json refused
together with a timeout error message after a long wait of aproximately 40 seconds. Of course Internet permission has already been added.
This happens randomly and it usually does after first run of Garbage Collector.
After spending days trying to debug it, I finally did a system reboot and this behaviour totally disappeared.
But, given I spent so much time on it (thinking that I was badly leaking something), I would still like to:
Understand what was going on
Understand if I am correctly profiling memory leaks
1: Understand what was going on:
The screen that shows up when starting the app, is the fragment that calls the AsyncTask responsible of updating the fragment UI itself (it is assigned to the first Action Bar tab).
As soon as the app started I began to continuosly rotate the screen to see what would happen to the memory. The screenshot below is from Android Studio memory profiler.
The first connection-timeout error usually occurred right after first run of Garbage Collector, after I had filled up all available memory by rotating the device many times.
At this point it happened that the fragment UI failed at being updated by AsyncTask (which was stuck processing the apparently unresponsive connection). The web server would not receive the HTTP request at all, and even if I rotated the screen again - in order for the Activity and Fragment to restart - subsequent AsyncTask's did not work too and no new HTTP requests would be made.
Of course I've been catching all exceptions and, at the beginning of onPostExecute() I had to do if (arrayOfJSONobjs == null) { return; } in order to avoid feeding in a null object to the subsequent fragment UI's building methods.
So, what do you think could have happened to make the connection work like that? How is that that after reboot I am not seeing that again? I've tried disabling antivirus, firewall, and checked if router or web server were applying some kind of protection for too many consecutive requests. (My device connects to the web server from the internet, using my public IP). Nothing worked, except reboot. The only thing I'm left with thinking is.. possibly some bug in Android Studio which got in the middle of the requests at some time?
2: Am I correctly understanding memory allocation and GC?
Looking at the code, do you think there is some place where I could possibly be leaking the context?
Is what I see in the memory profiler screenshot the expected good behaviour for a non leaking app? I mean, am I supposed to see memory being filled up even when there is no leaking (provided that then it gets garbage collected) ?
I don't know how to better put this, but am I expected to see this kind of graph when everything is going ok? As you can see, the first time, the GC is only invoked when memory is completely filled up, but afterwards GC triggers in sooner, when there is still some memory available (I was still rotating the device though). Is this normal?
Despite the errors above (but still possibly related to them, in case memory leaking is actually happening): I am unsure about having to pass both the view and the context to the AsyncTask object. Could I just pass only one of those and infer the other one from it, in order to minimize as much as possible the references I am passing?
Cleaning up: the subquestion about whether or not TableLayout is a good fit for the layout I'm trying to build has been moved to another question.
Code:
MainActivity.java
package com.mydom.demoapp;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import com.mydom.demoapp.adapter.TabsPagerAdapter;
public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
private String[] tabs = { "Music", "Movies", "News"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
// on swiping the viewpager make respective tab selected
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
if (item.getItemId() == android.R.id.home) {
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// on tab selected show appropriate fragment
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onStop(){
super.onStop();
Log.d("mytag", "MainActivity: onStop entered");
}
}
TabsPageAdapter.java
package com.mydom.demoapp.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.mydom.demoapp.MusicFragment;
import com.mydom.demoapp.MoviesFragment;
import com.mydom.demoapp.NewsFragment;
// This adapter provides fragment views to tabs.
public class TabsPagerAdapter extends FragmentPagerAdapter{
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new MusicFragment();
case 1:
return new MoviesFragment();
case 2:
return new NewsFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
}
MusicFragment.java (responsible for instantiating and launching an AsyncTask)
package com.mydom.demoapp;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mydom.demoapp.async_task.AsyncTaskRunner;
public class MusicFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public static MusicFragment newInstance(String param1, String param2) {
MusicFragment fragment = new MusicFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
public MusicFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
Log.d("mytag", "MusicFragment: onCreate entered");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.d("janfry", "MusicFragment: onCreateView entered");
return inflater.inflate(R.layout.fragment_music, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d("mytag", "MusicFragment: onViewCreated entered");
runner = new AsyncTaskRunner();
runner.execute(this.getActivity(), view);
// I am passing it the context (by getting the activity) and the view so that it will know where to update the UI.
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
#Override
public void onStop(){
super.onStop();
Log.d("mytag", "MusicFragment: onStop entered");
}
}
AsyncTaskRunner.java
package com.mydom.demoapp.async_task;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.mydom.demoapp.R;
import com.mydom.demoapp.Utils;
import org.apache.http.HttpResponse;
// import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
// import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
// import org.json.JSONException;
import org.json.JSONObject;
// import java.io.IOException;
// import java.net.SocketTimeoutException;
// import java.util.concurrent.TimeoutException;
public class AsyncTaskRunner extends AsyncTask<Object, String, JSONArray> {
// These will be set by doInBackground() according to what the fragment passed to it
// I am declaring them as instance variables because I'll need them in the onPostExecute method too, so to have a ref to the frag to update.
// By the way, can I infer one from the other someway?
Context contextRef;
View viewRef;
#Override
protected void onPreExecute(){
Log.d("janfry", "AsyncTaskRunner: onPreExecute entered");
}
#Override
protected JSONArray doInBackground(Object... params){
Log.d("mytag", "AsyncTaskRunner: doInBackground entered");
contextRef = (Context) params[0];
viewRef = (View) params[1];
HttpResponse response;
String str = "";
JSONArray arrayOfJSONObjects = null;
final HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpClient myClient = new DefaultHttpClient(httpParams);
HttpGet myConnection = new HttpGet("http://123.123.123.123:80/notes.json");
try {
response = myClient.execute(myConnection);
str = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Throwable t) {
t.printStackTrace();
}
try{
arrayOfJSONObjects = new JSONArray(str);
} catch ( Throwable t) { t.printStackTrace(); }
try {
Log.d("mytag", arrayOfJSONObjects.getString(0));
} catch (Throwable t) {
t.printStackTrace();
}
return arrayOfJSONObjects;
}
#Override
protected void onProgressUpdate(String... notused){
}
#Override
protected void onPostExecute(JSONArray arrayOfJSONobjs) {
Log.d("mytag", "AsyncTaskRunner: onPostExecute entered");
TableLayout tab_lay = (TableLayout) viewRef.findViewById(R.id.musicTableLayout);
tab_lay.removeAllViews();
TextView[] arrayOfTextViews;
arrayOfTextViews = new TextView[arrayOfJSONobjs.length()];
for(int pos = 0; pos < arrayOfJSONobjs.length(); pos++) {
// and let's populate it with textviews...
TextView textViewForObjName = new TextView(contextRef);
try {
JSONObject oneJsonObj; // will hold the parsed JSON for one obj
oneJsonObj = arrayOfJSONobjs.getJSONObject(pos);
textViewForObjName.setText(oneJsonObj.getString("name"));
} catch (Throwable t) {
t.printStackTrace();
}
textViewForObjName.setHeight(Utils.dip(contextRef, 30));
textViewForObjName.setBackgroundColor(Color.parseColor("#ABCABC"));
// let's add the text_view we built to the Array
arrayOfTextViews[pos] = textViewForObjName;
} // we now have an array of textviews, that has not been added to the UI yet.
// I want to populate the array with 3 textviews per row.
// Is it a good idea to use this layout for this way of laying out content?
// Would you have done that differently?
TableRow table_row = new TableRow(contextRef);
int col_counter = 0;
for (TextView aTextView : arrayOfTextViews) {
table_row.addView(aTextView);
col_counter++;
if (col_counter == 3) {
tab_lay.addView(table_row);
table_row = new TableRow(contextRef);
col_counter = 0;
}
}
}
}
#corsair992 is suggesting (it's just a guess) that "it may be that you were exceeding some maximum limit of concurrent connections allowed in Apache's DefaultHttpClient or elsewhere."
I advised her/him to put the above comment in a proper answer (together with other observations s/he did), but s/he said that it's just a guess and not a complete answer.
Still to me it's the most reasonable hypothesis and I think it deserves full visibility and attention so I am saving it as an answer myself so that maybe it can be further commented and expanded (please upvote the original #corsair992 comment under my question).

Android development using Google Tag Manager and dataLayer

I'm new to this Google Tag Manager stuff and I kinda got my ears tangled trying to test it.
Here's what I've done:
Created a GTM account;
Created a container;
Created a custom image tag;
Added rule always to the custom image tag;
Now here's my code:
package com.google.android.tagmanager.examples.helloworld;
import com.google.tagmanager.Container;
import com.google.tagmanager.ContainerOpener;
import com.google.tagmanager.ContainerOpener.OpenType;
import com.google.tagmanager.TagManager;
import com.google.tagmanager.DataLayer;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
import android.telephony.*;
import android.provider.*;
/**
* An {#link Activity} that reads background and text color from a local
* Json file and applies those colors to text view.
*/
public class MainActivity extends Activity {
private static final String TAG = "GTMExample";
private static final String CONTAINER_ID = "GTM-PJNXHL";
private static final String OS = "os";
private static final String DEVICE_IMEI = "device_imei";
private static final String DEVICE_ANDROID_ID = "device_android_id";
private static final String GOOGLE_AD_ID = "google_ad_id";
private static String deviceImei = "";
private static String androidId = "";
private static String googleAdId = "";
// Set to false for release build.
private static final Boolean DEVELOPER_BUILD = true;
private Container container;
private DataLayer dataLayer;
private TelephonyManager telephonyManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
if (DEVELOPER_BUILD) {
StrictMode.enableDefaults();
}
// iau singletonul de tagmanager
TagManager tagManager = TagManager.getInstance(this);
ContainerOpener.ContainerFuture containerFuture = ContainerOpener.openContainer(
tagManager, CONTAINER_ID, OpenType.PREFER_NON_DEFAULT, null);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
// This call may block (for up to the timeout specified in
// ContainerOpener.openContainer). For an example that shows how to use a splash
// screen to avoid blocking, see cuteanimals example.
container = containerFuture.get();
dataLayer = tagManager.getDataLayer();
// Modify the background-color and text-color of text based on the value
// from configuration.
updateVars();
}
private void updateVars() {
Log.i(TAG, "image_test");
TextView textView = (TextView) findViewById(R.id.hello_world);
textView.setText(OS);
}
public void colorButtonClicked(View view) {
Log.i(TAG, "colorButtonClicked");
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("Getting vars");
deviceImei = telephonyManager.getDeviceId();
androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
Info adInfo = null;
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(this.getBaseContext().getApplicationContext());
} catch (Exception e) {
System.out.println(e.getMessage());
}
googleAdId = adInfo.getId();
alertDialog.setMessage(deviceImei);
dataLayer.push(DEVICE_IMEI, deviceImei);
dataLayer.push(DEVICE_ANDROID_ID, androidId);
dataLayer.push(GOOGLE_AD_ID, googleAdId);
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,
"OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
alertDialog.show();
updateVars();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
What I want is to push the deviceImei, androidId and googleAdId using DataLayer.
My questions are:
How do I test and see that the data is pushed using dataLayer?
How do I test and see if the tag has been fired with the data from the dataLayer?
Where do I test to see that the tag has been traked?
Thank you!
One way is to use Google Analytics event with your data and the same rule. You'll see your data in GA if everything is correct.

Is it possible to intercept taking screenshot event when my app is in the foreground

Is it possible to intercept taking screenshot event (or create a listener for it) when my app is in the foreground? I want to execute some own code when a screenshot is taken by vol down+power key.
No, sorry, you do not get control on a screenshot. If your objective is to prevent your app from having a screenshot taken (e.g., security reasons), use FLAG_SECURE:
public class FlagSecureTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(LayoutParams.FLAG_SECURE,
LayoutParams.FLAG_SECURE);
setContentView(R.layout.main);
}
}
The way to do this task is to add a file observer on the screenshot directory. Writing sample code below to observe the file path
The screenshot file observer
package com.example.main;
import android.os.Environment;
import android.os.FileObserver;
import android.util.Log;
public class ScreenshotObserver extends FileObserver {
private static final String PATH = Environment.getExternalStorageDirectory().toString() + "/Pictures/Screenshots";
private static final String TAG = "ScreenshotObserver";
private ScreenshotListener listener;
private String mLastTakenPath;
ScreenshotObserver(ScreenshotListener listener) {
super(PATH);
this.listener = listener;
Log.d(TAG, PATH);
}
#Override
public void onEvent(int event, String path) {
Log.d(TAG, String.format("Detected new file added %s", path));
if (path==null || event != FileObserver.CLOSE_WRITE)
Log.d(TAG, "Don't care.");
else if (mLastTakenPath!=null && path.equalsIgnoreCase(mLastTakenPath))
Log.d(TAG, "This event has been observed before.");
else {
mLastTakenPath = path;
listener.onScreenshotTaken(path);
Log.d(TAG, "Send event to listener.");
}
}
public void start() {
super.startWatching();
Log.d(TAG, "Start Watching.");
}
public void stop() {
super.stopWatching();
Log.d(TAG, "Stop Watching.");
}
}
Activity that implement the file observer
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity implements ScreenshotListener{
private ScreenshotObserver obs;
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
obs = new ScreenshotObserver(this);
obs.start();
setContentView(R.layout.activity_main);
}
#Override
public void onScreenshotTaken( String path ) {
TextView t = (TextView)findViewById(R.id.monText);
t.setText("Screenshot taken ! " + path);
}
}

EditTextPreferences Validation

Can anyone tell me what is wrong with this code. For some reason the OnSharedPreferencesChanged is not being called when changing the value. I am trying to check if the PIN entered is equal to 2 digits or no. But for it just doesnt work..
can anyone help me out.
Thanks.!
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.util.Log;
import android.widget.Toast;
public class PrefsActivity extends PreferenceActivity implements
OnSharedPreferenceChangeListener {
EditTextPreference editPreference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
this.editPreference = ((EditTextPreference) getPreferenceScreen()
.findPreference("userPass"));
Log.d("TAG","before sharedPreferenceChanged");
}
#Override
protected void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
Log.d("TAG","In SharedPreferences");
if (sharedPreferences.getString("userPass", null).length() != 2) {
Log.d("TAG","lenght is less than 1");
Toast.makeText(this, "Pin has to be 2 digits only",
Toast.LENGTH_LONG).show();
this.editPreference.setText(null);
return;
} else {
Toast.makeText(this, "Pin set", Toast.LENGTH_LONG).show();
}
// TODO Auto-generated method stub
}
Try setting the setOnPreferenceChangeListener for your editPreference in onCreate(), put your validation code inside this callback.
Reading the docs, they say OnSharedPreferenceChangeListener is called when the shared preference is changed(is already changed). In the other hand the setOnPreferenceChangeListener is triggered "when this Preference is changed by the user (but before the internal state has been updated)"

Categories

Resources