Android api30 whatsapp package name issue [duplicate] - android-studio

Opening Whatsapp with intent is not working in android OS 11 but working fine up to android (OS) 10 devices, It displays the message "Whatsapp app not installed in your phone" on the android 11 device. Does anyone have a solution for this?
String contact = "+91 9999999999"; // use country code with your phone number
String url = "https://api.whatsapp.com/send?phone=" + contact;
try {
PackageManager pm = context.getPackageManager();
pm.getPackageInfo("com.whatsapp", PackageManager.GET_ACTIVITIES);
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
context.startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
Toast.makeText(mContext, "Whatsapp app not installed in your phone",Toast.LENGTH_LONG).show();
e.printStackTrace();
}

There are new changes in android 11 of package visibility.
You need to add a new section queries under you app's <manifest> tag with desired package name:
<manifest package="com.example.app">
<queries>
<package android:name="com.whatsapp" />
</queries>
...
</manifest>

Instead of using wildcards, it's more explicit to add both package names:
<manifest package="com.example.app">
<queries>
<package android:name="com.whatsapp"/>
<package android:name="com.whatsapp.w4b"/>
</queries>
...
</manifest>

"com.whatsapp"
can also be the culprit.
i was also boggled with this message.
the issue was "whatsApp business app" which has package name:
"com.whatsapp.w4b"
used following code to find out which one is installed:
String appPackage="";
if (isAppInstalled(ctx, "com.whatsapp.w4b")) {
appPackage = "com.whatsapp.w4b";
//do ...
} else if (isAppInstalled(ctx, "com.whatsapp")) {
appPackage = "com.whatsapp";
//do ...
} else {
Toast.makeText(ctx, "whatsApp is not installed", Toast.LENGTH_LONG).show();
}
private boolean isAppInstalled(Context ctx, String packageName) {
PackageManager pm = ctx.getPackageManager();
boolean app_installed;
try {
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
app_installed = true;
} catch (PackageManager.NameNotFoundException e) {
app_installed = false;
}
return app_installed;
}

Rather than adding each Package names in , you can add:
**<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />**
to your AndroidManifest.xml file in your project.
I was also bothering with the same, this permission allowed me to troubleshoot my issue/error.

To open Whatsapp or Whatsapp Business on button click use the below code.
To open whatsapp
Intent intent1 = getPackageManager().getLaunchIntentForPackage("com.whatsapp");
startActivity(intent1);
To open Business whatsapp
Intent intent2 = getPackageManager().getLaunchIntentForPackage("com.whatsapp.w4b");
startActivity(intent2);

Related

Block or Remove all incoming notification of other apps programatically in android studio

Hello everyone , hope you all are doing good. I want to ask how to remove or block any incoming notification (coming from other apps like whats app, instagram etc) in android programatically.
Below is the code snippet i am using to block the notification but it's not working.
class BlockNotification : NotificationListenerService() {
override fun onBind(intent: Intent): IBinder? {
return super.onBind(intent)
}
#RequiresApi(Build.VERSION_CODES.Q)
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.d("Msg", "Notification arrived ${sbn.packageName},${sbn.id},${sbn.key},${sbn.uid}")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
cancelNotification(sbn.packageName, sbn.tag, sbn.id)
} else {
cancelNotification(sbn.key)
}
}
#RequiresApi(Build.VERSION_CODES.Q)
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// Implement what you want here
Log.d("Msg", "Notification Removed")
clearNotofication(sbn.uid)
cancelNotification(sbn.key)
}
private fun clearNotofication(notificationId: Int) {
val ns = NOTIFICATION_SERVICE
val nMgr = this.getSystemService(ns) as NotificationManager
nMgr.cancel(notificationId)
}
}
Also declared the service in manifest file.
<service
android:name=".utils.BlockNotification"
android:exported="true"
android:label="#string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
<meta-data
android:name="android.service.notification.default_filter_types"
android:value="conversations|alerting" />
<meta-data
android:name="android.service.notification.disabled_filter_types"
android:value="ongoing|silent" />
</service>
If anyone have any idea , please let me know !!
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
you can get the context by signing context in your class's parameter
then you can clear all of the notifications in your notification Bar
notificationManager.cancelAll();
or in your case remove only one notification by using it's id like you did in your last function
notificationManager.cancle(notification_id);
or using with a tag I don't think you want this but to let you know it is exist
notificationManager.cancle(your_tag, notification_id);
you check the Doc for explanation

Android [10/Q/API29] Unsupported path /storage/emulated/0/ [duplicate]

I'm unable to create directory in android 10. It's working on devices till android Oreo.
I tried two ways for creating folders.
Using File.mkdir():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
success = f.mkdir();
}
Here, the variable success is always false which means the directory isn't created.
Using Files.createDirectory():
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
if (!f.isFile()) {
if (!(f.isDirectory())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Files.createDirectory(Paths.get(f.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), R.string.unable_to_download, Toast.LENGTH_LONG).show();
}
} else {
f.mkdir();
}
}
which causes this exception:
pzy64.pastebinpro W/System.err: java.nio.file.AccessDeniedException: /storage/emulated/0/Pastebin
pzy64.pastebinpro W/System.err: at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:391)
pzy64.pastebinpro W/System.err: at java.nio.file.Files.createDirectory(Files.java:674)
I've implemented the run-time permissions and
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
are all set.
As was first disclosed back in March 2019, you no longer have access by default to arbitrary locations on external storage or removable storage on Android 10+. This includes Environment.getExternalStorageDirectory() and other methods on Environment (e.g., getExternalStoragePublicDirectory().
For Android 10 and 11, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.
Otherwise, your choices are:
Use methods on Context, such as getExternalFilesDir(), to get at directories on external storage into which your app can write. You do not need any permissions to use those directories on Android 4.4+. However, the data that you store there gets removed when your app is uninstalled.
Use the Storage Access Framework, such as ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT.
If your content is media, you can use MediaStore to place the media in standard media locations.
For Android 10, you can add
android:requestLegacyExternalStorage="true"
to your element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work. This fix will not work on Android R and higher though, so this is only a short-term fix.
There are more restrictions in Android API 30
you can only write in your app-specific files
File dir_ = new File(context.getFilesDir(), "YOUR_DIR");
dir_.mkdirs();
or in the external storage of your app Android/data
File dir_ = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
UPDATE
this answer provided another solution https://stackoverflow.com/a/65744517/8195076
UPDATE
another way is to grant this permission in manifest
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
like this answer https://stackoverflow.com/a/66968986/8195076
This works for me and I think it's functional on Android 10>
ContentResolver resolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Folder Example");
String path = String.valueOf(resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues));
File folder = new File(path);
boolean isCreada = folder.exists();
if(!isCreada) {
folder.mkdirs();
}
You can use public directory to save files in Android 11 like this:
dir = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getPath()
+ "/foldername");
if (!dir.exists()) {
dir.mkdir();
Toast.makeText(getApplicationContext(), "not exist", Toast.LENGTH_SHORT).show();
}
Since Q beta 4 it's possible to opt-out of that feature by:
targeting api 28 (or lower)
using requestLegacyExternalStorage manifest attribute:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
only use
android:requestLegacyExternalStorage="true"
in manifests

Creating VSIX package for TFS Source control explorer context menu extension

I am trying to create VSIX package to extend functionality of TFS 2012 source control right click context menu when clicking on branch.
I don't want to use Add-in. this has to be package which other developers can directly install.
The customized menu items need to appear in the source control explorer contextual menu after they install the extension. I am not able to get any sample for this requirement or not able to get proper documentation source. One of sample I found is "TFS community branch tool", which is kind of similar functionality I am looking for, but I am not able to get the source code of it.
Appreciate your help.
I assume that you are familiar with the .vsct file, command/menu/groups Guids/Id stuff (all this is documented in MSDN). So, the question would be which is the Guid/Id of the group inside the context menu of Source Control Explorer.
Guessing that you may want your command below the "Get Latest Version" menu entry of the context menu of a file, the code would be:
<Commands package="guidVSMyPackagePkg">
<Buttons>
<Button guid="guidVSMyPackageCmdSet" id="cmdidMyCommand" priority="0x0100" type="Button">
<Parent guid="guidSourceControlExplorerMenuGroup" id="SourceControlExplorerMenuGroupId"/>
<Strings>
<ButtonText>My Command</ButtonText>
</Strings>
</Button>
</Buttons>
</Commands>
<Symbols>
<GuidSymbol name="guidVSMyPackagePkg" value="{...}" />
<GuidSymbol name="guidVSMyPackageCmdSet" value="{...}">
<IDSymbol name="cmdidMyCommand" value="0x0100" />
</GuidSymbol>
<GuidSymbol name="guidSourceControlExplorerMenuGroup" value="{ffe1131c-8ea1-4d05-9728-34ad4611bda9}">
<IDSymbol name="SourceControlExplorerMenuGroupId" value="0x1111" />
</GuidSymbol>
</Symbols>
Building upon Carlos Quintero's answer:
If you need to put the command in any other location in the Source Control Explorers context menu, you need the right Id. Using EnableVSIPLogging you can only find information for commands and their parent menus, but not the groups.
In order to find Group Ids (or any other ID for that matter) used in the Source Control Explorer you can follow these steps (for VS2015):
Decompile Microsoft.VisualStudio.TeamFoundation.VersionControl.dll (using JetBrains dotPeek for instance).
Open Resources\HatPackage.resources.
Look up 1000.ctmenu and copy the Base64 data.
Convert the data from Base64 to bytes.
Save the bytes in a file as TfsMenu.cto (the extension needs to be .cto and it needs to be in a location with write rights for the next step to work).
Run "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VSSDK\VisualStudioIntegration\Tools\Bin\vsct.exe" TfsMenu.cto TfsMenu.vsct to decompile the file.
Now you have the original .vsct file that was used to make the TFS plugin. In here you can look up all IDs.
To get you started finding the menuitems in TfsMenu.vsct, you can enable EnableVSIPLogging:
Add HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\14.0\General\EnableVSIPLogging as DWORD32 with value 1.
Now, in Visual Studio, when Holding Ctrl+Shift while hovering menus or clicking menu items in the Source Control Explorer, a messagebox pops up with information about that item, including the GUID and ID of that menu/menuitem
#Erik I was so happy to run across your explanation for extracting the vsct as I trying very hard to figure out how to do that very thing. Just to expound upon your answer I converted it into code. Sharing here in case anyone is interested.
static void Main(string[] args)
{
/*
Extract menus from extensions
http://stackoverflow.com/questions/29831181/creating-vsix-package-for-tfs-source-control-explorer-context-menu-extension
*/
try
{
string vsctPath = ConfigurationManager.AppSettings["VSCTPath"];
if (!File.Exists(vsctPath))
{
WriteConsole("The path to the vsct.exe could not be found. Please edit the app.config to set the right executable path.", ConsoleColor.Yellow);
return;
}
//TODO: Convert to a command line argument
string dllPath = #"C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\ManagementStudio\Extensions\Application\Microsoft.SqlServer.Management.SqlStudio.Explorer.dll";
var assembly = Assembly.LoadFrom(dllPath);
if (assembly == null)
{
WriteConsole("Could not load assembly.", ConsoleColor.Yellow);
return;
}
var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(n => Regex.IsMatch(n, #"VSPackage\.resources", RegexOptions.IgnoreCase));
if (String.IsNullOrWhiteSpace(resourceName))
{
WriteConsole("Could find VSPackage.resources in assembly.", ConsoleColor.Yellow);
return;
}
var resourceManager = new ResourceManager(Path.GetFileNameWithoutExtension(resourceName), assembly);
if (resourceManager == null)
{
WriteConsole("Could find load the resource " + resourceName + ".", ConsoleColor.Yellow);
return;
}
var menus = resourceManager.GetObject("Menus.ctmenu") as byte[];
if (menus == null)
{
WriteConsole("Could find Menus.ctmenu resource in VSPackage.resources.", ConsoleColor.Yellow);
return;
}
string dir = Path.Combine(Path.GetTempPath(), "PackageMenus");
string fileName = Path.GetFileNameWithoutExtension(dllPath) + ".cto";
Directory.CreateDirectory(dir);
Directory.SetCurrentDirectory(dir);
File.WriteAllBytes(Path.Combine(dir, fileName), menus);
string processArgs = String.Format(#"{0} {1}.vsct", fileName, fileName);
var pi = new ProcessStartInfo(vsctPath, processArgs);
pi.UseShellExecute = false;
pi.RedirectStandardError = true;
pi.RedirectStandardOutput = true;
var ret = Process.Start(pi);
var output = ret.StandardOutput.ReadToEnd();
var errors = ret.StandardError.ReadToEnd();
Console.WriteLine(output);
if (!string.IsNullOrWhiteSpace(errors))
{
Console.Write("Errors: ");
WriteConsole(errors, ConsoleColor.Red);
}
else
{
Console.WriteLine("New files written to: " + dir);
}
}
catch(Exception ex)
{
WriteConsole(ex.ToString(), ConsoleColor.Red);
}
finally
{
Console.WriteLine("\r\nPress any key to continue.");
Console.ReadKey(true);
}
}
private static void WriteConsole(string message, ConsoleColor color = ConsoleColor.White)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ResetColor();
}

How to open Instagram Posting Screen in Android?

Is there something equivalent to instagram://camera in Android like in iOS?
No, as I know there are not somthing equivalent but you can post photo(or video, just change a little bit) directly to instagram posting dialog:
public void postInstagramPhoto(File photo, String message, OnPostingCompleteListener onPostingCompleteListener) {
String instagramPackage = "com.instagram.android";
String errorMessage = "You should install Instagram app first";
if(isPackageInstalled(instagramPackage, getActivity())){
Intent normalIntent = new Intent(Intent.ACTION_SEND);
normalIntent.setType("image/*");
normalIntent.setPackage(instagramPackage);
File media = new File(photo.getAbsolutePath());
Uri uri = Uri.fromFile(media);
normalIntent.putExtra(Intent.EXTRA_STREAM, uri);
normalIntent.putExtra(Intent.EXTRA_TEXT, message);
getActivity().startActivity(normalIntent);
} else {
Toast.makeText(getActivity(), "Install Instagram first.", Toast.LENGHT_SHORT).show();
}
}
you can check other popular methods from asne-instagram here
or maybe if you need to add more social networks check this

Magento: Remove a Shipping Method in Frontend

I'm currenty working on a shipping module extension that is used for an order-import script to set to every order the same shipping cost and shipping code.
Everythings works fine but the problem that is, that the shipping method is visible in frontend. I will release this extension later in magento connect, so its not pissible to edit frontend templates.
Does anyone know how to disable the carrier in frontend without disableing the module in backend or changeing the status to inactive and without editing templates? (e.g. a custom block that declines displaying)
Thanks to everyone! Mru
EDIT:
I've tried your tip like this, but it doesn't work:
<blocks>
<checkout>
<rewrite>
<onepage_shipping_method_availible>XXX_XXX_Block_Checkout_Onepage_Shipping_Method_Available</onepage_shipping_method_availible>
</rewrite>
</checkout>
</blocks>
and created this class:
class XXX_XXX_Block_Checkout_Onepage_Shipping_Method_Available extends Mage_Checkout_Block_Onepage_Shipping_Method_Available
{
public function getShippingRates()
{
if (empty($this->_rates)) {
$this->getAddress()->collectShippingRates()->save();
$groups = $this->getAddress()->getGroupedAllShippingRates();
return $this->_rates = $groups;
}
return $this->_rates;
}
}
(I don't know why it is not displayed correctly...)
Thanks for your held, MRu
EDIT2:
Sorry for being so stupid.. The above posted code would work if i were not unable to write 'availalbe'...
Thanks!
You can hide shipping method from front end with observer, write this code in config.xml
<frontend>
<events>
<sales_quote_collect_totals_before>
<observers>
<frontend_shipping_rates_sales_quote_collect_totals_before>
<class>yourmodule/observer</class>
<method>hideShippingMethods</method>
</frontend_shipping_rates_sales_quote_collect_totals_before>
</observers>
</sales_quote_collect_totals_before>
</events>
Second in Observer.php use this code
public function hideShippingMethods( Varien_Event_Observer $observer )
{
if (Mage::getDesign()->getArea() === Mage_Core_Model_App_Area::AREA_FRONTEND)
{
$quote = $observer->getEvent()->getQuote();
$store = Mage::app()->getStore($quote->getStoreId());
$carriers = Mage::getStoreConfig('carriers', $store);
$hiddenMethodCode = 'freeshipping';
foreach ($carriers as $carrierCode => $carrierConfig)
{
if( $carrierCode == $hiddenMethodCode )
{
$store->setConfig("carriers/{$carrierCode}/active", '0');
}
}
}
}
You need to overload the Mage_Checkout_Block_Onepage_Shipping_Method_Available::getShippingRates() method

Resources