password protected uninstall in android 4+ versions [programmatically] - android

i want my app to have a password protected uninstall ... (like app lock)
im using folling code it works on Android 2.3 but not on Android 4+ versions
MANIFEST FILE
<receiver android:name="fyp.invisibleink.UninstallIntentReceiver" >
<intent-filter android:priority="0" >
<action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<data android:scheme="package" />
</intent-filter>
</receiver>
Uninstalling Activity code
ublic class Uninstalling extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uninstalling);
// listener
Button settingsBtn = (Button) findViewById(R.id.btnu);
settingsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final EditText e1 = (EditText) findViewById(R.id.etpass);
final String pass = e1.getText().toString();
SharedPreferences cupSetting = getSharedPreferences(
"cuppassword", Context.MODE_PRIVATE);
String mypass = cupSetting.getString("pass", "");
if (pass.equals(mypass)) {
Toast.makeText(getApplicationContext(),
"password is correct!", Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(),
"press OK to uninstall!", Toast.LENGTH_LONG).show();
finish();
} else {
Toast.makeText(getApplicationContext(),
"Access Denied! try again", Toast.LENGTH_LONG)
.show();
e1.setText("");
}
}
});
}
UninstallReceveier
public class UninstallIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// fetching package names from extras
String[] packageNames = intent
.getStringArrayExtra("android.intent.extra.PACKAGES");
if (packageNames != null) {
for (String packageName : packageNames) {
if (packageName != null
&& packageName.equals("com.example.invisibleink")) {
// User has selected our application under the Manage Apps
// settings
// now initiating background thread to watch for activity
new ListenActivities(context).start();
}
}
}
}
// ///////////////////////////////
class ListenActivities extends Thread {
boolean exit = false;
ActivityManager am = null;
Context context = null;
public ListenActivities(Context con) {
context = con;
am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
}
#Override
public void run() {
Looper.prepare();
while (!exit) {
// get the info from the currently running task
List<ActivityManager.RunningTaskInfo> taskInfo = am
.getRunningTasks(MAX_PRIORITY);
String activityName = taskInfo.get(0).topActivity
.getClassName();
Log.d("topActivity", "CURRENT Activity ::" + activityName);
if (activityName
.equals("com.android.packageinstaller.UninstallerActivity")) {
// User has clicked on the Uninstall button under the Manage
// Apps settings
Intent intent = new Intent(context, Uninstalling.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
exit = true;
// do whatever pre-uninstallation task you want to perform
// here
// show dialogue or start another activity or database
// operations etc..etc..
// context.startActivity(new Intent(context,
// MyPreUninstallationMsgActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} else if (activityName
.equals("com.android.settings.ManageApplications")) {
// back button was pressed and the user has been taken back
// to Manage Applications window
// we should close the activity monitoring now
exit = true;
}
}
Looper.loop();
}
}
}
Permissioms
<uses-permission android:name="android.permission.GET_TASKS" />

I am not positive, so please correct me if I'm wrong but this might have been removed as a security feature. A malicious app might be able to create a password and avoid the app from being removed creating further damage on the device. Like I said, I could be wrong but this is a guess that seems legit. I noticed that 4+ did a couple things for security because of a lot of malicious stuff and exploits happening within 3rd party apps.

Related

How to check MIUI autostart permission programmatically?

I need to check programmatically if the auto start permission for my app in MIUI phone is on or off. Facebook and whatsapp have this permission already enabled by default , how can I do so?
For now it's not possible.
As it's completely depend on their operating system API's and customisation. Even developers have requested for this on XIOMI's official forums but there is no response from there side.
Till now even i am finding an answer to this question but nothing helped me.
For the time being it will be only possible for rooted phones. i.e. making customisation in their firmware by becoming super user. But this is not at all advisable as it may damage user's phone.
EDIT 1
You can redirect user to autostart permission's settings page for enabling your app using following code
String manufacturer = "xiaomi";
if (manufacturer.equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
//this will open auto start screen where user can enable permission for your app
Intent intent1 = new Intent();
intent1.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent1);
}
EDIT 2
I have recently used Mi A1 from XIOMI which have stock android (not miui) so this phone does not have autostart permission settings from miui. So take care while navigating user to the settings in such devices because it will not work here.
100% working for oppo, vivo, xiomi, letv huawei, and honor
just call this function
private void addAutoStartup() {
try {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
} else if ("oppo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
} else if ("vivo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
} else if ("Letv".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity"));
} else if ("Honor".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
}
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
startActivity(intent);
}
} catch (Exception e) {
Log.e("exc" , String.valueOf(e));
}
}
This is not a perfect solution by any means and it requires some testing, but I've been able to detect the autostart permission on my Xiaomi device with it.
The autostart permission allows apps to be started by receiving an implicit broadcast intent. This method consists of scheduling an implicit broadcast with AlarmManager, killing the app and checking if the broadcast caused it to respawn. A second explicit intent is also scheduled just to make sure that the app is started eventually.
public class AutostartDetector extends BroadcastReceiver {
// I've omitted all the constant declaration to keep this snippet concise
// they should match the values used in the Manifest
public static void testAutoStart(Context context) {
long now = System.currentTimeMillis();
// this ID is for matching the implicit and explicit intents
// it might be unnecessary
String testId = Long.toHexString(now);
Intent implicitIntent = new Intent(ACTION_IMPLICIT_BROADCAST);
// the category is set just to make sure that no other receivers handle the broadcast
implicitIntent.addCategory(CATEGORY_AUTOSTART);
implicitIntent.putExtra(EXTRA_TEST_ID, testId);
PendingIntent implicitPendingIntent =
PendingIntent.getBroadcast(context, REQUEST_CODE_IMPLICIT_BROADCAST, implicitIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent explicitIntent = new Intent(ACTION_EXPLICIT_BROADCAST);
explicitIntent.addCategory(CATEGORY_AUTOSTART);
explicitIntent.setComponent(new ComponentName(context, AutostartDetector.class));
explicitIntent.putExtra(EXTRA_TEST_ID, testId);
PendingIntent explicitPendingIntent =
PendingIntent.getBroadcast(context, REQUEST_CODE_EXPLICIT_BROADCAST, explicitIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// calling commit() makes sure that the data is written before we kill the app
// again, this might be unnecessary
getSharedPreferences(context).edit().putInt(testId, TestStatus.STARTED).commit();
// the explicit intent is set with an additional delay to let the implicit one be received first; might require some fine tuning
alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY, implicitPendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY + EXPLICIT_INTENT_DELAY, explicitPendingIntent);
// kill the app - actually kind of tricky, see below
SelfKiller.killSelf(context);
}
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = getSharedPreferences(context);
String testId = intent.getStringExtra(EXTRA_TEST_ID);
if (testId == null) {
Log.w(TAG, "Null test ID");
return;
}
if (!sharedPreferences.contains(testId)) {
Log.w(TAG, "Unknown test ID: " + testId);
return;
}
String action = intent.getAction();
if (ACTION_IMPLICIT_BROADCAST.equals(action)) {
// we could assume right here that the autostart permission has been granted,
// but we should receive the explicit intent anyway, so let's use it
// as a test sanity check
Log.v(TAG, "Received implicit broadcast");
sharedPreferences.edit().putInt(testId, TestStatus.IMPLICIT_INTENT_RECEIVED).apply();
} else if (ACTION_EXPLICIT_BROADCAST.equals(action)) {
Log.v(TAG, "Received explicit broadcast");
int testStatus = sharedPreferences.getInt(testId, -1);
switch (testStatus) {
case TestStatus.STARTED:
// the implicit broadcast has NOT been received - autostart permission denied
Log.d(TAG, "Autostart disabled");
sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, false).apply();
notifyListener(false);
break;
case TestStatus.IMPLICIT_INTENT_RECEIVED:
// the implicit broadcast has been received - autostart permission granted
Log.d(TAG, "Autostart enabled");
sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, true).apply();
notifyListener(true);
break;
default:
Log.w(TAG, "Invalid test status: " + testId + ' ' + testStatus);
break;
}
}
}
private interface TestStatus {
int STARTED = 1;
int IMPLICIT_INTENT_RECEIVED = 2;
}
Receiver declaration in the manifest:
<receiver android:name=".autostart.AutostartDetector">
<intent-filter>
<category android:name="com.example.autostart.CATEGORY_AUTOSTART"/>
<action android:name="com.example.autostart.ACTION_IMPLICIT_BROADCAST"/>
<action android:name="com.example.autostart.ACTION_EXPLICIT_BROADCAST"/>
</intent-filter>
</receiver>
Killing the app reliably is another problem. I've been using this helper method:
public static void killSelf(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(context.getPackageName());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// this is all we can do before ICS. luckily Xiaomi phones have newer system versions :)
System.exit(1);
return;
}
// set up a callback so System.exit() is called as soon as all
// the activities are finished
context.registerComponentCallbacks(new ComponentCallbacks2() {
#Override
public void onTrimMemory(int i) {
if (i == TRIM_MEMORY_UI_HIDDEN) {
Log.v(TAG, "UI Hidden");
System.exit(1);
}
}
/* ... */
});
// see below
ActivityTracker.getInstance().finishAllActivities();
}
ActivityTracker is another utility that keeps track of activity lifecycles. Make sure to register it in the Application subclass.
#RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public final class ActivityTracker implements Application.ActivityLifecycleCallbacks {
private final ArraySet<Activity> mCreatedActivities = new ArraySet<>();
public static ActivityTracker getInstance() {
return Holder.INSTANCE;
}
public static void init(Application application) {
application.registerActivityLifecycleCallbacks(getInstance());
}
public static void release(Application application) {
ActivityTracker activityTracker = getInstance();
application.unregisterActivityLifecycleCallbacks(activityTracker);
activityTracker.mCreatedActivities.clear();
}
public void finishAllActivities() {
// iterate over active activities and finish them all
for (Activity activity : mCreatedActivities) {
Log.v(TAG, "Finishing " + activity);
activity.finish();
}
}
public Set<Activity> getCreatedActivities() {
return Collections.unmodifiableSet(mCreatedActivities);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mCreatedActivities.add(activity);
}
#Override
public void onActivityDestroyed(Activity activity) {
mCreatedActivities.remove(activity);
}
private static final class Holder {
private static final ActivityTracker INSTANCE = new ActivityTracker();
}
/* ... */
}
You might also want to stop all the services just to be sure.
In addition to Nikhil's answer:
First of all, some apps like Facebook, Whatsapp are whitelisted from Xiomi by default that means auto start permission will automatically be on for these apps.
I also didn't find any way to check for auto start permission if it's enabled or not and enable it programmatically. Though as above answer suggests we can redirect user to auto start permission activity but when we have to redirect user we still don't know and also this will not work in all of the Xiomi devices.
So I used an alternative for my sync adapter to work. I stored a boolean variable named "isSyncAdapterRunning" in shared preferences and set the value of it every time sync adapter runs. This way I'll be able to know if my sync adapter is working or not.
//in my sync adapter
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.e("TAG", "SyncStarted");
performSync(true);
}
public static void performSync(boolean fromSyncAdapterClass){
//write your code for sync operation
if(fromSyncAdapterClass){
setValueOfIsSyncAdapterRunningVariable();
}
}
I made other background service to perform same task if sync adapter is not working.
//In my other background service
public class BackgroundSyncService extends IntentService {
public BackgroundSyncService() {
super("BackgroundSyncService");
}
#Override
protected void onHandleIntent(Intent intent) {
SyncAdapter.performSync(false);
}
}
Now start sync adapter:
// start your sync adapter here
//And after that just start that service with a condition
if(!getValueOfIsSyncAdapterRunningVariable()){
startService(new Intent(context, BackgroundSyncService.class));
}
So basically I'm running another service to perform same task in background if my sync adapter is not working and the best thing is only one of them will run at a time.
Above code will fail if user turn on auto start permission and turn off again because value of boolean variable is already set. For that you can set value of boolean variable to default once in every 24Hrs.
Hope this helps.
For now it's not possible.
As it's completely depend on their operating system API's and customization. But i implemented a fix using SharedPreference. It doesn't solved the problem but it prevents app from opening setting screen everytime app is opened. Example :
if (AppPref.getAutoStart(context).isEmpty() && AppPref.getAutoStart(context).equals("")) {
enableAutoStart();
}
private void enableAutoStart() {
if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
new AlertDialog.Builder(context)
.setTitle("Enable AutoStart")
.setMessage("Please allow this app to always run in the background,else our services can't be accessed.")
.setNegativeButton("Deny", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
AppPref.setAutoStart(context, "");
dialog.dismiss();
}
})
.setPositiveButton("ALLOW", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
try {
AppPref.setAutoStart(context, "1");
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, "Can't perform action", Toast.LENGTH_SHORT).show();
}
dialog.dismiss();
}
})
.create()
.show();
}
}
This code worked for me. Simple and easy . Credit
private State getAutoStartState(Activity activity) throws Exception {
Class<?> clazz;
try {
clazz = Class.forName(CLAZZ);
} catch (ClassNotFoundException ignored) {
// we don't know if its enabled, class
// is not found, no info
return State.NO_INFO;
}
final Method method = getMethod(clazz);
if (method == null) {
// exception raised while search the method,
// or it doesn't exist
return State.NO_INFO;
}
// the method is a public method, It's still
// better to do this
method.setAccessible(true);
// the target object is null, because the
// method is static
final Object result = method.invoke(null, getActivity(),
getActivity().getPackageName());
// the result should be an Int
if (!(result instanceof Integer))
throw new Exception();
final int _int = (int) result;
if (_int == ENABLED)
return State.ENABLED;
else if (_int == DISABLED)
return State.DISABLED;
return State.UNKNOWN;
}
private Method getMethod(Class<?> clazz) {
try {
return clazz.getDeclaredMethod("getApplicationAutoStart",
Context.class, String.class);
} catch (Exception ignored) {
// this should not happen, probably
// MIUI version is updated, lets give a last try
return null;
}
}
public void checkMIUIAutoStart(Activity activity) throws Exception {
if (getAutoStartState(activity) == State.DISABLED) {
String manufacturer = "xiaomi";
if (manufacturer.equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
//this will open auto start screen where user can enable permission for your app
Intent intent1 = new Intent();
intent1.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent1);
}
}else {
Toast.makeText(activity, "Auto-start is enabled.", Toast.LENGTH_SHORT).show();
}
}
You cannot check whether autorun permission is enabled or not because autorun feature is provided by customised os only not by android os like mi, vivo, oppo, letv etc
This is a workaround tested on MI, Honor and vivo phones.
To check whether os is customised like miui, honor ui copy and paste this method in activity, fragment or util class
public static void getAutoStartPermission(final Activity context) {
final String build_info = Build.BRAND.toLowerCase();
switch (build_info) {
case "xiaomi":
Utilities.Companion.showAutorunDialog(context);
break;
case "letv":
Utilities.Companion.showAutorunDialog(context);
break;
case "oppo":
Utilities.Companion.showAutorunDialog(context);
break;
case "vivo":
Utilities.Companion.showAutorunDialog(context);
break;
case "Honor":
Utilities.Companion.showAutorunDialog(context);
break;
default:
break;
}
}
Where
fun showAutorunDialog(context: Context) {
val builder = AlertDialog.Builder(context)
//set title for alert dialog
builder.setTitle("Alert")
//set message for alert dialog
builder.setMessage("Enable Autostart permission for this app if its disabled in app settings in order to run application in background.")
builder.setCancelable(true)
//performing positive action
builder.setPositiveButton("Enable") { _, _ ->
addAutoStartup(context)
}
// Create the AlertDialog
var vpnDialog = builder.create()
// Set other dialog properties
vpnDialog!!.setCancelable(false)
vpnDialog!!.show()
}
private fun addAutoStartup(context:Context) {
try {
val intent = Intent()
val manufacturer = Build.MANUFACTURER
if ("xiaomi".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")
} else if ("oppo".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")
} else if ("vivo".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")
} else if ("Letv".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")
} else if ("Honor".equals(manufacturer, ignoreCase = true)) {
intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")
}
val list: List<ResolveInfo> = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
if (list.size > 0) {
context.startActivity(intent)
}
} catch (e: java.lang.Exception) {
Log.e("exc", e.toString())
}
}
You could use this library to check the autostart permission state on MIUI 10, 11 and 12.
https://github.com/XomaDev/MIUI-autostart
// make sure device is MIUI device, else an
// exception will be thrown at initialization
Autostart autostart = new Autostart(applicationContext);
State state = autostart.getAutoStartState();
if (state == State.DISABLED) {
// now we are sure that autostart is disabled
// ask user to enable it manually in the settings app
} else if (state == State.ENABLED) {
// now we are also sure that autostart is enabled
}
To check if permission enabled, I just starting a foreground service and check if is running.
Service:
class ExtraPermissionStateService: Service() {
companion object {
private var instance: ExtraPermissionStateService? = null
fun isAppCanRunOnBackground(context: Context): Boolean {
val serviceIntent = Intent(context, ExtraPermissionStateService::class.java)
context.startService(serviceIntent)
return instance != null
}
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
instance = this
}
override fun onDestroy() {
super.onDestroy()
instance = null
}
}
call it:
ExtraPermissionStateService.isAppCanRunOnBackground(context)
And don't forget on the manifest:
<service android:name=".helpers.utils.ExtraPermissionStateService"/>
I have tried the below solution and it worked for me. If the "Auto Start" is enabled it will return "true", if not it will return "false".
public class CustomPermissionCheck {
private static final String TAG = "CustomPermissionCheck";
private Context context;
private static final int APP_AUTO_START_PERMISSION_CODE = 10008;
public CustomPermissionCheck(Context context) {
this.context = context;
}
public boolean isAutoStartEnabled() {
try {
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Method method = AppOpsManager.class.getMethod("checkOpNoThrow", int.class, int.class, String.class);
int result = (int) method.invoke(appOpsManager, APP_AUTO_START_PERMISSION_CODE, android.os.Process.myUid(), context.getPackageName());
boolean isEnabled = result == AppOpsManager.MODE_ALLOWED;
return isEnabled;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
You have to do allow and deny for system permissions.
below is the code:
private boolean checkPermission(){
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
if (result == PackageManager.PERMISSION_GRANTED){
return true;
} else {
return false;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Snackbar.make(view,"Permission Granted, Now you can access location data.",Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(view,"Permission Denied, You cannot access location data.",Snackbar.LENGTH_LONG).show();
}
break;
}
}

directly start Activity if user has already registered

I am new in android development. i want my application to directly launch MainActivity if the User has already registered. how can i do this.
this is my MainActivity
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
Button btnTip, btnApp, btndos, btnAbout, btnServices;
ConnectionDetector cd;
AsyncTask<Void, Void, Void> mRegisterTask;
public static String name;
public static String email;
public static String contact;
public static String imei;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.app_bar);
toolbar.setTitle("Dental Application");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
btnTip = (Button) findViewById(R.id.tips);
btndos = (Button) findViewById(R.id.dos);
btnApp = (Button) findViewById(R.id.appointments);
btnAbout = (Button) findViewById(R.id.about);
btnServices = (Button) findViewById(R.id.services);
// Alert dialog manager
AlertDialogManager alert = new AlertDialogManager();
cd = new ConnectionDetector(getApplicationContext());
// Check if Internet present
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(MainActivity.this,
"Internet Connection Error",
"Please check your Internet connection", false);
// stop executing code by return
return;
}
Intent i = getIntent();
name = i.getStringExtra("name");
email = i.getStringExtra("email");
contact = i.getStringExtra("contact");
imei = i.getStringExtra("imei");
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);
//lblMessage = (TextView) findViewById(R.id.lblMessage);
registerReceiver(mHandleMessageReceiver, new IntentFilter(
DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, name, email, regId, contact, imei);
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
btnTip.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TipsActivity.class);
startActivity(intent);
}
});
btndos.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, DosActivity.class);
startActivity(intent);
}
});
btnApp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, BookAppointmennts.class);
startActivity(intent);
}
});
btnAbout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, AboutUsActivity.class);
startActivity(intent);
}
});
btnServices.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, ServicesActivity.class);
startActivity(intent);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Receiving push messages
* */
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message
* depending upon your app requirement
* For now i am just displaying it on the screen
* */
// Showing received message
//lblMessage.append(newMessage + "\n");
Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
// Releasing wake lock
WakeLocker.release();
}
};
#Override
protected void onDestroy() {
if (mRegisterTask != null) {
mRegisterTask.cancel(true);
}
try {
unregisterReceiver(mHandleMessageReceiver);
GCMRegistrar.onDestroy(this);
} catch (Exception e) {
Log.e("UnRegister Receiver", "> " + e.getMessage());
}
super.onDestroy();
}
}
and the RegisterActivity
public class RegisterActivity extends Activity {
// alert dialog manager
AlertDialogManager alert = new AlertDialogManager();
// Internet detector
ConnectionDetector cd;
// UI elements
EditText txtName;
EditText txtEmail;
EditText txtContact;
// Register button
Button btnRegister;
String imei;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
cd = new ConnectionDetector(getApplicationContext());
// Check if Internet present
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(RegisterActivity.this,
"Internet Connection Error",
"Please connect to working Internet connection", false);
// stop executing code by return
return;
}
// Check if GCM configuration is set
if (SERVER_URL == null || SENDER_ID == null || SERVER_URL.length() == 0
|| SENDER_ID.length() == 0) {
// GCM sernder id / server url is missing
alert.showAlertDialog(RegisterActivity.this, "Configuration Error!",
"Please set your Server URL and GCM Sender ID", false);
// stop executing code by return
return;
}
txtName = (EditText) findViewById(R.id.txtName);
txtEmail = (EditText) findViewById(R.id.txtEmail);
txtContact = (EditText) findViewById(R.id.contact);
btnRegister = (Button) findViewById(R.id.btnRegister);
TelephonyManager mngr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
imei = mngr.getDeviceId();
/*
* Click event on Register button
* */
btnRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Read EditText dat
String name = txtName.getText().toString();
String email = txtEmail.getText().toString();
String contact = txtContact.getText().toString();
// Check if user filled the form
if (name.trim().length() > 0 && email.trim().length() > 0 && contact.trim().length()>0) {
// Launch Main Activity
Intent i = new Intent(getApplicationContext(), MainActivity.class);
// Registering user on our server
// Sending registraiton details to MainActivity
i.putExtra("name", name);
i.putExtra("email", email);
i.putExtra("contact", contact);
i.putExtra("imei", imei);
startActivity(i);
finish();
} else {
// user doen't filled that data
// ask him to fill the form
alert.showAlertDialog(RegisterActivity.this, "Registration Error!", "Please enter your details", false);
}
}
});
}
}
i am using GCM. the user is first registered and MainActivity is Displayed. Next time when the user opens the application i want directly MainActivity to be displayed. how can i do this. Can anyone please help me.
You will have to make LauncherActivity like SplashScreen in which check from shared prefrences or sqlite data that user is already registered or not
then by checking this transfer to corresponding activity.
If the user is not registered then show Registration Screen and when user register then save info in Sqlite or sharedpreferences or any other way.
If the user is already registered the show HomeScreen
First of all just post only the code that needs modification, you've posted all of the code in that Java file of yours. We could be more helpful if your code isn't cluttered.

Android root activity sometimes started spontaneously without any user actions

I have a strange issue which I cannot explain. In the manifest file the launch activity of my app is defined as follows:
<activity
android:name="com.xxx.xxx.xxx.StartupActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.Light.NoTitleBar"
android:screenOrientation="sensorPortrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
In the StartUpActivity the following check is performed:
protected void startIntent() {
Intent intent;
if (checkCurrentProfile()) {
Notifier.showHttpToast(R.string.toastLoggedIn);
//try to update the device token in the database
Request.updateDeviceToken();
intent = new Intent(this, GameListActivity.class);
} else {
intent = new Intent(this, RegisterActivity.class);
}
startActivity(intent);
finish();
}
So if the user has a valid account the GameListActivity is shown as root activity:
<activity
android:name="com.xxx.xxx.xxx.xxx.GameListActivity"
android:label="#string/app_name"
android:theme="#style/MyTheme"
android:screenOrientation="sensorPortrait" >
</activity>
The issue now is the following: sometimes the system brings the root activity to the front spontaneously without any user actions. It only occurs sometimes, but I can't figure out the cause. Can anyone help me out here?
The StartUpActivity looks like this:
public class StartupActivity extends StartupCoreActivity implements OnRegisterGCMListener {
private IabHelper mHelper;
private IabHelper.QueryInventoryFinishedListener mQueryInventoryFinishedListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerOnRegisterGCMListener(this);
if (!registerGCMneeded()) {
initInAppBilling();
}
}
#Override
public void registerGCMfinished() {
initInAppBilling();
}
private void initInAppBilling() {
boolean hasPremium = Prefs.getBoolValue(getResources().getString(R.string.pref_key_upgrade_premium), false);
if (hasPremium) {
//unlocking contents not needed
startIntent();
} else {
Prefs.storeValue(getResources().getString(R.string.pref_key_upgrade_premium), false);
mHelper = new IabHelper(this, C.Billing.BILLING_KEY);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (result.isSuccess()) {
queryInventory();
} else {
startIntent();
}
}
});
}
}
private void queryInventory() {
String[] products = {C.Billing.ITEM_SKU};
mQueryInventoryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
if (result.isSuccess()) {
checkPremiumVersion(inv);
} else {
startIntent();
}
}
};
mHelper.queryInventoryAsync(true, Arrays.asList(products), mQueryInventoryFinishedListener);
}
private void checkPremiumVersion(Inventory inv) {
if (inv.hasPurchase(C.Billing.ITEM_SKU)) {
Request.updPremiumVersion();
Prefs.storeValue(getResources().getString(R.string.pref_key_upgrade_premium), true);
Notifier.showHttpToast(R.string.toastPremiumContentsUnlocked);
}
startIntent();
}
}
And the StartupCoreActivity looks like this:
public class StartupCoreActivity extends Activity {
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = xxxx;
GoogleCloudMessaging mGcm;
Context mContext;
String mRegId;
/**
* Substitute you own sender ID here. This is the project number you got
* from the API Console, as described in "Getting Started."
*/
String SENDER_ID = "xxxxxxxxxx";
private OnRegisterGCMListener mOnRegisterGCMListener = null;
public void registerOnRegisterGCMListener(OnRegisterGCMListener listener) {
mOnRegisterGCMListener = listener;
}
protected boolean registerGCMneeded() {
mContext = getApplicationContext();
// Check device for Play Services APK.
if (checkPlayServices()) {
// If this check succeeds, proceed with normal processing.
// Otherwise, prompt user to get valid Play Services APK.
mGcm = GoogleCloudMessaging.getInstance(this);
mRegId = getRegistrationId(mContext);
if (mRegId.isEmpty()) {
registerInBackground();
return true;
} else {
// note we never called setContentView()
return false;
}
}
return false;
}
protected void startIntent() {
Intent intent;
if (checkCurrentProfile()) {
Notifier.showHttpToast(R.string.toastLoggedIn);
//try to update the device token in the database
Request.updateDeviceToken();
intent = new Intent(this, GameListActivity.class);
} else {
intent = new Intent(this, RegisterActivity.class);
}
startActivity(intent);
finish();
}
private boolean checkCurrentProfile() {
KUPlayer me = G.getMySelf();
if (me.getPlayerId() <= 0) {
//database was not present yet and has been created
//or database was present, but profile cannot be read anymore
// make sure Login screen appears ONLY if PlayerID cannot be retrieved anymore
if (G.getPlayerID() <=0) {
Prefs.storeValue(Prefs.PREF_KEY_PWD_SAVED, false);
return false;
}
}
return true;
}
// You need to do the Play Services APK check here too.
#Override
protected void onResume() {
super.onResume();
checkPlayServices();
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
finish();
}
return false;
}
return true;
}
/**
* Registers the application with mGcm servers asynchronously.
* <p>
* Stores the registration ID and the app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (mGcm == null) {
mGcm = GoogleCloudMessaging.getInstance(mContext);
}
mRegId = mGcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + mRegId;
// Persist the mRegId - no need to register again.
storeRegistrationId(mContext, mRegId);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
// note we never called setContentView()
if (mOnRegisterGCMListener != null) {
mOnRegisterGCMListener.registerGCMfinished();
}
}
}.execute(null, null, null);
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private static int getAppVersionCode(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
private static String getAppVersionName(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionName;
} catch (NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* Stores the registration ID and the app versionCode in the application's
* {#code SharedPreferences}.
*
* #param mContext application's mContext.
* #param mRegId registration ID
*/
private void storeRegistrationId(Context context, String regId) {
Prefs.storeValue(Prefs.PREF_KEY_DEVICE_TOKEN, regId);
Prefs.storeValue(Prefs.PREF_KEY_APP_VERSION_CODE, getAppVersionCode(context));
Prefs.storeValue(Prefs.PREF_KEY_APP_VERSION_NAME, getAppVersionName(context));
AppRate.resetAfterUpdate();
}
/**
* Gets the current registration ID for application on mGcm service, if there is one.
* <p>
* If result is empty, the app needs to register.
*
* #return registration ID, or empty string if there is no existing
* registration ID.
*/
private String getRegistrationId(Context context) {
String registrationId = Prefs.getStringValue(Prefs.PREF_KEY_DEVICE_TOKEN);
if (registrationId.isEmpty()) {
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing mRegId is not guaranteed to work with the new
// app version.
int registeredVersion = Prefs.getIntValue(Prefs.PREF_KEY_APP_VERSION_CODE);
int currentVersion = getAppVersionCode(context);
if (registeredVersion != currentVersion) {
return "";
}
return registrationId;
}
}
I guess it has to do with the following known Android bug:
How to prevent multiple instances of an activity when it is launched with different intents
And as suggested put the following code in the onCreate method of the rootActivity:
// Possible work around for market launches. See http://code.google.com/p/android/issues/detail?id=2373
// for more details. Essentially, the market launches the main activity on top of other activities.
// we never want this to happen. Instead, we check if we are the root and if not, we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
I tested it and when you start your app from Google Play store in stead of launch screen, then indeed finish() is called from above code.

Create Custom Lock Screen to get username/ password to authenticate user in our android application

I have device tracker application, where user needs to login so that devices is assigned to it.
But, now I want user should not able to use that devices until user have authenticated and should be available until user sing-out from that device ?
I want to retrieve password entered by user when he unlocks the screen and want to use it for my application authentication it's self and if password do not match I will unlock screen again.
I'm trying following code but still not basically able to lock and unlock screens using password.
public class AdminSettingsActivity extends Activity {
private EditText baseURLEditText;
private Button saveBaseURL;
private TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
saveBaseURL = (Button) findViewById(R.id.saveBaseURLBtn);
baseURLEditText = (EditText) findViewById(R.id.base_url_edit);
tv = (TextView) findViewById(R.id.text_admin_message);
tv.append(" " + DeviceTrackerApp.DEFAULT_BASE_URL);
saveBaseURL.setOnClickListener(new OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View v) {
String url = baseURLEditText.getText().toString().trim();
if (!url.isEmpty()) {
try {
if (URLUtil.isValidUrl(url)) {
new ValidateServerURL(AdminSettingsActivity.this).execute(url);
} else {
showInvalidURLToast();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
protected void showInvalidURLToast() {
// get your custom_toast.xml ayout
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_layout,
(ViewGroup) findViewById(R.id.toast_layout_root));
// set a dummy image
ImageView image = (ImageView) layout.findViewById(R.id.image_invalid_pwd);
image.setImageResource(R.drawable.invalid_pwd);
// set a message
TextView text = (TextView) layout.findViewById(R.id.text_invalid_password);
text.setText("Invalid URL! Can't Save.");
// Toast...
Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();
}
public void setURLStatus(int statusCode) {
if (statusCode == 200) {
DeviceTrackerApp.setBaseURL(baseURLEditText.getText().toString());
Toast.makeText(getApplicationContext(), "Valid URL Saved Successful",
Toast.LENGTH_LONG).show();
tv.setText("\nYour Setting saved successfuly. Press back button to go home screen\n");
} else {
showInvalidURLToast();
baseURLEditText.setText("");
}
}
}
and My DeviceTrackerAdmin class is
public class DeviceTrackerAdmin extends DeviceAdminReceiver {
static SharedPreferences getSamplePreferences(Context context) {
return context.getSharedPreferences(DeviceAdminReceiver.class.getName(), 0);
}
static String PREF_PASSWORD_QUALITY = "password_quality";
static String PREF_PASSWORD_LENGTH = "password_length";
static String PREF_MAX_FAILED_PW = "max_failed_pw";
void showToast(Context context, CharSequence msg) {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onEnabled(Context context, Intent intent) {
showToast(context, "Sample Device Admin: enabled");
}
#Override
public CharSequence onDisableRequested(Context context, Intent intent) {
return "This is an optional message to warn the user about disabling.";
}
#Override
public void onDisabled(Context context, Intent intent) {
showToast(context, "Sample Device Admin: disabled");
}
#Override
public void onPasswordChanged(Context context, Intent intent) {
showToast(context, "Sample Device Admin: pw changed");
}
#Override
public void onPasswordFailed(Context context, Intent intent) {
showToast(context, "Sample Device Admin: pw failed");
}
#Override
public void onPasswordSucceeded(Context context, Intent intent) {
showToast(context, "Sample Device Admin: pw succeeded");
}
}
I also defined reciever in AndroidMenifest.xml
<receiver
android:name=".DeviceTrackerAdmin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="com.abc.devicetracker.DeviceTrackerApp"
android:resource="#layout/policies" >
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" >
</action>
</intent-filter>
</meta-data>
</receiver>
But, every time onActivityResult() on
`if (resultCode == RESULT_OK)` **OR** `if (resultCode == Activity.RESULT_OK)` condition fails as `resultCode is 0 only` So for Device locking I need to root my mobile.
when u got password is correct or incorrect the password then use following code
//Get the window from the context
WindowManager wm = Context.getSystemService(Context.WINDOW_SERVICE);
//Unlock if password is incorrect
http://developer.android.com/reference/android/app/Activity.html#getWindow()
Window window = getWindow();
window.addFlags(wm.LayoutParams.FLAG_DISMISS_KEYGUARD);
//Lock device if password is correct
DevicePolicyManager mDPM;
mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
I have found a github project and I'm modifying it as per my requirements.
Thanks to All for your efforts.
https://github.com/wordpress-mobile/Android-PasscodeLock
https://github.com/swapnilvkotwal/LockScreenApp
And found this answer helpful Creating an Android Lock Screen App.

Android InAppBilling - what to do when user presses the buy button?

I set up the "Dungeons" InAppBilling example locally and I am ready to try it out, but I am a bit confused. I have a button like this:
Button donate = (Button)findViewById(R.id.donate);
donate.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
// But what do I do here? :)
}
});
And when it is called, what do I need to do to actually go to the pay screen on android store?
Thanks!
I better suggest you to use this code as this example is quiet simple and easy to handle at first .. the things you have to do is
http://blog.blundell-apps.com/simple-inapp-billing-payment/
download the sample project code from the above link (Having Description of code and download link at bottom)
in your android project where you want to implement in app billing, create package com.android.vending.billing and place IMarketBillingService.aidl (you can find this and all files mention below in the project you downloaded in step 1)
place following utility files in any package and correct import statements accordingly.
* BillingHelper.java
* BillingReceiver.java
* BillingSecurity.java
* BillingService.java
* C.java
place the public key (you can find it in developer console in the bottom section of edit profile) in the BillingSecurity.java in line saying String base64EncodedPublicKey = "your public key here"
Declare the following permission (outside the application tag), service and receiver (Inside the application tag) in your manifest like shown below(can also see manifest which is along the code for reference)
//outside the application tag
<uses-permission android:name="com.android.vending.BILLING" />
// Inside the application tag
<service android:name=".BillingService" />
<receiver android:name=".BillingReceiver">
<intent-filter>
<action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
<action android:name="com.android.vending.billing.RESPONSE_CODE" />
<action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
</intent-filter>
</receiver>
place the following code as mentioned with there places in your activity where purchase is being held.
//at the starting of your onCreate()
startService(new Intent(mContext, BillingService.class));
BillingHelper.setCompletedHandler(mTransactionHandler);
//outside onCreate() Within class
public Handler mTransactionHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
Log.i(TAG, "Transaction complete");
Log.i(TAG, "Transaction status: "+BillingHelper.latestPurchase.purchaseState);
Log.i(TAG, "Item purchased is: "+BillingHelper.latestPurchase.productId);
if(BillingHelper.latestPurchase.isPurchased()){
//code here which is to be performed after successful purchase
}
};
};
//code to initiate a purchase... can be placed in onClickListener etc
if(BillingHelper.isBillingSupported()){
BillingHelper.requestPurchase(mContext, "android.test.purchased");
// where android.test.purchased is test id for fake purchase, when you create products through developer console you can set a code to pass the id(which is given on developer console while creating a product) of the item which is selected for purchase to intiate purchase of that item.
} else {
Log.i(TAG,"Can't purchase on this device");
// Do Anything Heer to show user that purchase not possible on this device
}
Note: To do a test purchase you need to put the public key in BillingSecurity.java as mentioned above secondly you need to upload the apk to the developer console(you can leave it uupublished and unactive) and thirdly you need a real android device(emulator wouldn't work) having updated play store app.
Note: the account needed for in app purchase and described in all above discussion is not just simple publisher account its publisher account embedded with google merchant wallet account. The details can be found in link below.
http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113468
1)download
http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-download
2)add
http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-add-aidl
3)add permission in your android manifest file
http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-permission
now your project should look like this...
4) place the public key (you can find it in developer console in the
bottom section of edit profile) in the Security.java in line saying
String base64EncodedPublicKey = "your public key here"
5) and finally your activity which have button should be look like this
public class YourActivity extends Activity implements OnClickListener {
String issueProductId = "Your Product ID";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.updates);
SetInAppBilling();
Button donate = (Button) findViewById(R.id.donate);
donate.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
if (mBillingService.requestPurchase(issueProductId, null)) {
} else {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
Log.i("tag", "Can't purchase on this device");
}
}
});
}
public void register() {
ResponseHandler.register(mDungeonsPurchaseObserver);
}
public void unregister() {
ResponseHandler.unregister(mDungeonsPurchaseObserver);
}
public void close_unbind() {
if (mPurchaseDatabase != null)
// mPurchaseDatabase.close();
if (mBillingService != null)
mBillingService.unbind();
// stopService(new Intent(this, BillingService.class));
}
/**
* Called when this activity becomes visible.
*/
#Override
protected void onStart() {
super.onStart();
register();
}
/**
* Called when this activity is no longer visible.
*/
#Override
protected void onStop() {
unregister();
super.onStop();
}
#Override
protected void onDestroy() {
close_unbind();
super.onDestroy();
}
private static final String TAG = "YourActivity";
private static final String DB_INITIALIZED = "db_initialized";
// private static final String Dir_Check = "Dir_Check";
private DungeonsPurchaseObserver mDungeonsPurchaseObserver;
private Handler mHandler;
private BillingService mBillingService;
private PurchaseDatabase mPurchaseDatabase;
private static final int DIALOG_CANNOT_CONNECT_ID = 1;
private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;
private Cursor mOwnedItemsCursor;
public void SetInAppBilling() {
mHandler = new Handler();
mDungeonsPurchaseObserver = new DungeonsPurchaseObserver(mHandler);
mBillingService = new BillingService();
mBillingService.setContext(this);
mPurchaseDatabase = new PurchaseDatabase(this);
mOwnedItemsCursor = mPurchaseDatabase
.queryAllPurchasedHistroyTabelItems();
startManagingCursor(mOwnedItemsCursor);
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
// Check if billing is supported.
ResponseHandler.register(mDungeonsPurchaseObserver);
if (!mBillingService.checkBillingSupported()) {
showDialog(DIALOG_CANNOT_CONNECT_ID);
}
}
private class DungeonsPurchaseObserver extends PurchaseObserver {
public DungeonsPurchaseObserver(Handler handler) {
super(YourActiviy.this, handler);
}
#Override
public void onBillingSupported(boolean supported) {
Log.i(TAG, "supportedCheck: " + supported);
if (Consts.DEBUG) {
Log.i(TAG, "supported: " + supported);
}
if (supported) {
restoreDatabase();
} else {
showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
}
}
#Override
public void onPurchaseStateChange(PurchaseState purchaseState,
String itemId, int quantity, long purchaseTime,
String developerPayload) {
if (Consts.DEBUG) {
Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " "
+ purchaseState);
}
if (developerPayload == null) {
} else {
}
Log.e(TAG, "onPurchaseStateChangeCheck: " + "onPurchaseStateChange");
if (purchaseState == PurchaseState.PURCHASED) {
/** TODO: */
Toast.makeText(
mContext,
"You successfully upgraded to the entire Volume One. Enjoy!",
Toast.LENGTH_SHORT).show();
finish();
}
}
#Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
if (Consts.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
if (Consts.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
} else {
if (Consts.DEBUG) {
Log.i(TAG, "purchase failed");
}
}
}
#Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.d(TAG, "completed RestoreTransactions request");
}
// Update the shared preferences so that we don't perform
// a RestoreTransactions again.
SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.commit();
mOwnedItemsCursor = mPurchaseDatabase
.queryAllPurchasedHistroyTabelItems();
Log.d(TAG, String.valueOf(mOwnedItemsCursor.getCount()));
startManagingCursor(mOwnedItemsCursor);
if (mOwnedItemsCursor.getCount() > 0) {
Log.d(TAG, "Updating the DB");
Toast.makeText(
mContext,
"You successfully upgraded to the entire Volume One. Enjoy!",
Toast.LENGTH_SHORT).show();
finish();
}
} else {
if (Consts.DEBUG) {
Log.d(TAG, "RestoreTransactions error: " + responseCode);
}
}
}
}
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_CANNOT_CONNECT_ID:
return createDialog(R.string.cannot_connect_title,
R.string.cannot_connect_message);
case DIALOG_BILLING_NOT_SUPPORTED_ID:
return createDialog(R.string.billing_not_supported_title,
R.string.billing_not_supported_message);
default:
return null;
}
}
private Dialog createDialog(int titleId, int messageId) {
String helpUrl = replaceLanguageAndRegion(getString(R.string.help_url));
if (Consts.DEBUG) {
Log.i(TAG, helpUrl);
}
final Uri helpUri = Uri.parse(helpUrl);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(titleId)
.setIcon(android.R.drawable.stat_sys_warning)
.setMessage(messageId)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, null)
.setNegativeButton(R.string.learn_more,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
Intent intent = new Intent(Intent.ACTION_VIEW,
helpUri);
startActivity(intent);
}
});
return builder.create();
}
/**
* Replaces the language and/or country of the device into the given string.
* The pattern "%lang%" will be replaced by the device's language code and
* the pattern "%region%" will be replaced with the device's country code.
*
* #param str
* the string to replace the language/country within
* #return a string containing the local language and region codes
*/
private String replaceLanguageAndRegion(String str) {
// Substitute language and or region if present in string
if (str.contains("%lang%") || str.contains("%region%")) {
Locale locale = Locale.getDefault();
str = str.replace("%lang%", locale.getLanguage().toLowerCase());
str = str.replace("%region%", locale.getCountry().toLowerCase());
}
return str;
}
private void restoreDatabase() {
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
if (!initialized) {
mBillingService.restoreTransactions();
// Toast.makeText(this, "restoring...", Toast.LENGTH_LONG).show();
}
}
}
There are 2 ways
Maintain a database on your server end, and create a table for user+purchased list of products+expiry date
Or the client app to save a encrypted code on shared preferences (so that it cant be hacked easily)
Android API's dont provide you with any inventory apis to maintain your purchases.
I used the 2nd option.
-- single product purchase
store.purchase( { "android.test.purchased" } )
-- multi-item purchase
store.purchase( { "android.test.purchased", "android.test.canceled" } )
in reference to Getting Started with Android In-app Billing
this code maybe the one you are looking for
The sample in-app billing code from Google is a good start. I have posted a link to a tutorial I gave which is three parts. This link is the first of three. I hope it helps.
http://www.mobileoped.com/2012/04/06/android-google-play-in-app-billing-part-1/

Categories

Resources