How to use Activity attribute android:showForAllUsers in Xamarin? - xamarin

The attribute is not implemented in Xamarin. This mean I can't declare it as an attribute of my Activity Class like it should:
[Activity(Label = "#string/app_name", Theme = "#style/MainTheme.StopAlarm", LaunchMode = Android.Content.PM.LaunchMode.SingleTask, ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait, NoHistory = true)]
public class StopAlarmActivity : Activity
{
...
}
There's no ShowForAllUsers option.
The other option is to edit Properties => AndroidManifest.xml and add the activity manually like this:
<activity
android:name=".StopAlarmActivity"
android:label="#string/app_name"
android:theme="#style/MainTheme.StopAlarm"
android:showForAllUsers="true">
</activity>
But once I compile the final AndroidManifest.xml file contains two declarations, the manually added and the compiled one from the class declaration.
<activity android:name=".StopAlarmActivity" android:label="#string/app_name" android:theme="#style/MainTheme.StopAlarm" android:showForAllUsers="true"></activity>
<activity android:label="#string/app_name" android:launchMode="singleTask" android:noHistory="true" android:screenOrientation="portrait" android:theme="#style/MainTheme.StopAlarm" android:name="md5e24228758d0205525e724fe958bff865.StopAlarmActivity" />
That said, it looks like the only option is to edit the compiled AndroidManifest.xml file after each compilation. Which is a major breach for problems.
Any other way to accomplish it where I don't need to rely on remembering it every time I compile the app?

On your Activity attribute, applied a Name to avoid the MD5-based Java class auto-naming:
[Activity(Name = "com.sushihangover.MainActivity")]
In your manifest use the same fully-qualified name (no abbreviated dot notation) with the attributes you wish to apply to this activity:
<activity
android:name="com.sushihangover.MainActivity"
android:showForAllUsers="true"
android:icon="#mipmap/icon"
android:label="MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: All the attributes for this Activity need to be added within the manifest, not the Activity class attribute.
The final manifest entries will be merged correctly:
<activity android:name="com.sushihangover.MainActivity" android:showForAllUsers="true" android:icon="#mipmap/icon" android:label="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Related

How to configure my manifes in Xamarin for Android V12

My current manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cecop.cecop" android:installLocation="auto" android:versionCode="132" android:versionName="14.00">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:label="cecop" android:icon="#drawable/cecop">
<!--Especifique el número de versión de Google Play Services en el manifiesto y la clave de Google Maps V2 API. -->
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBLH0HotP0r5yfuX8xFESZhM5TS0PcluKs" />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<!-- Needed for Android >= Nougat for file access -->
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.cecop.cecop.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
<service android:name="com.cecop.cecop.ServicioSegundoPlano" android:exported="true"></service>
</application>
</manifest>
In the service and main activity I have this attributes
[Service(Exported = true, Name = "com.cecop.cecop.ServicioSegundoPlano")]
public class ServicioStartForeground : Service
{
...
}
[Activity(Label = "Cecop", Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{...
}
As I write in the manifest so you don't get the error in the publication on Google Play?
You have uploaded an APK or Android App Bundle that has an activity, an alias of activity, a service or an emission receiver with atnts filter, but without establishing the Android property: exported. This file cannot be installed on Android 12 or later versions.
You don't have to define anything in AndroidManifest.xml if you are using the [Service] attribute. Xamarin generates this for you.
The only change you need to make on Android 12, is that you need to add whether a Service is exported or not. Default should be false unless you need to access it from another App than yours.
If you are using something like Xamarin.Essentials or other libraries that also contain services, make sure they are up to date and also follow these rules about adding Exported property on their services.

How can I open an App using it own background service

I'm creating Xamarin.Forms App and it has a service that runs in the background monitoring if any messages arrive. If a message arrives, the service should open the App.
I tried to open the App using Intent (Dependency Service) and I also tried using Xamarin.Essentials. Neither way worked.
My last attempt was with Xamarin.Essentials and gave the following error:
[Error][1]
[1]: https://i.stack.imgur.com/5jPGf.png
This is my code using Intent (Dependency Service):
//Intent (Dependency Service)
string teste = "com.saferit.saferproject";
openAppManager = DependencyService.Get<IAppHandler>();
openAppManager.Initialize(teste);
openAppManager.LaunchApp();
[enter image description here][2]
[2]: https://i.stack.imgur.com/lLx3g.png
This is my native code for Android
public void LaunchApp()
{
Intent intent = new Intent();
intent.SetClassName(Package, "activity");
intent.AddFlags(ActivityFlags.NewTask);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
[Complete Native Code][3]
[3]: https://i.stack.imgur.com/G4zOV.png
This is my AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.saferit.saferproject" android:installLocation="preferExternal">
<uses-sdk android:minSdkVersion="27" android:targetSdkVersion="29" />
<!--<application android:label="SaferProject.Android"></application>-->
<application android:label="com.saferit.saferproject" android:icon="#drawable/logo">
<activity android:icon="#drawable/logo" android:label="com.saferit.saferproject" android:name="com.saferit.saferproject">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.saferit.saferproject" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
This is my attempt using Xamarin.Essential:
//Xamarin.Essentials
var appname = "com.saferit.saferproject://";
var supportsUri = await Launcher.CanOpenAsync(appname);
if (supportsUri)
await Launcher.OpenAsync(appname);
Looking for here at stackoverflow I found this question:
Open Notification list page when user clicks on navigation
I tried to implement it on my App but I also couldn't get it to work.
In all three cases the errors are very similar.
I think the problem is in the configuration of the URI of my App.
Can someone help me?

Google Places API search inconsistent

Google Places API behaves unexpectedly for a specific type of search.
I thought that the API returns a list of all places that is related to a query when 'type' is not specified but that doesn't seem to be the case. I get different (non-overlapping) results for the requests below, using same query "bergamo8":
https://maps.googleapis.com/maps/api/place/textsearch/xml?query=bergamo8&key=API_KEY
<PlaceSearchResponse>
<status>OK</status>
<result>
<name>Bergamo</name>
<type>locality</type>
<type>political</type>
<formatted_address>Bergamo, Province of Bergamo, Italy</formatted_address>
<geometry>
<location>
<lat>45.6982642</lat>
<lng>9.6772698</lng>
</location>
<viewport>
<southwest>
<lat>45.6625158</lat>
<lng>9.6205463</lng>
</southwest>
<northeast>
<lat>45.7238489</lat>
<lng>9.7136328</lng>
</northeast>
</viewport>
</geometry>
<icon>
https://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png
</icon>
<reference>
CmRbAAAA8T_6nvUrkTUF85gJtkVtFdbUccfYlcxVOziiUZ_HAsWHdySDg8cdPKvQD2wMjMx2oPc17nn4R3YaQDXbKViVyxHHf1qgWVwJ3yUHGygud4hUnY9aADoHSH-8U1l3xdaNEhD_SrAbwT9WGEQIedHS67AQGhTowbrLa_4LvWMfYSekJlYzOVyj5w
</reference>
<id>89666d6c7fc59efec1788477617d124d59a254f9</id>
<photo>
<photo_reference>
CmRaAAAAAFWrmgCoXKoske2yxr9a6EkTDMlL59VTQ2bJ_SWzLxGT5itDjXLegV1Geliqilz70Ve3fekX9LUa46NcdVWPCKFGw8P1XniuDx8ZSyoNhObzrFTkgOI6TajtzqaOyG8fEhCnQYNCt4A19laWACC_c4OnGhQxg1rTA9mRBcgZlN_iMt4dViX6HQ
</photo_reference>
<width>2560</width>
<height>1536</height>
<html_attribution>
Barbara Grassi
</html_attribution>
</photo>
<place_id>ChIJc65ivBFRgUcR0aTlC4_LL9M</place_id>
</result>
</PlaceSearchResponse>
https://maps.googleapis.com/maps/api/place/textsearch/xml?query=bergamo8&type=lodging&key=API_KEY
<PlaceSearchResponse>
<status>OK</status>
<result>
<name>Bergamo8</name>
<type>lodging</type>
<type>point_of_interest</type>
<type>establishment</type>
<formatted_address>
Piazza della Repubblica, 3, 24122 Bergamo BG, Italy
</formatted_address>
<geometry>
<location>
<lat>45.6979060</lat>
<lng>9.6674570</lng>
</location>
<viewport>
<southwest>
<lat>45.6965483</lat>
<lng>9.6660933</lng>
</southwest>
<northeast>
<lat>45.6992480</lat>
<lng>9.6687930</lng>
</northeast>
</viewport>
</geometry>
<rating>4.0</rating>
<icon>
https://maps.gstatic.com/mapfiles/place_api/icons/lodging-71.png
</icon>
<reference>
CmRbAAAAciLhIMD6BUcnZrkiI3og5zkv8iufp0MXe1UJ48ZnBZgc37dyohrPK8SuBVIl9vtnMaeuqiS1rRUq1IcfoK9Y-DKQj17jsK0QttB-2Q5PICXtL23ZOFABZwPKFMCHvoGSEhC2tTX2oEUtdtvJJElkvA24GhRxoVbZjb2mIzhlLwzZYZKfvcTN3A
</reference>
<id>443bfff8822b1f589bffc27a4e4f9e3201e99200</id>
<opening_hours>
<open_now>true</open_now>
</opening_hours>
<photo>
<photo_reference>
CmRaAAAAW37hcFzSRR3TQWPggrDHh7g5nizXfCmtKuif8y-nX4_q6oQdt7GHNWe5YPOrrqcSfs_1a0opZHnFzV1QBBbh1RYNN4D41yTzM03VpGtIpamTNWY9Gyyv7oAi3p4r460SEhAAqvPQOxucRXoKwmmsTmE4GhQ3wybwAY9EmBKDd6uprFgHq_QiEA
</photo_reference>
<width>2048</width>
<height>1335</height>
<html_attribution>
Bergamo8
</html_attribution>
</photo>
<place_id>ChIJhfjVaxFRgUcRolpKS-72w8M</place_id>
</result>
</PlaceSearchResponse>
Does anyone know if this is a bug or if there is a way to retrieve all types of places related to a query?
Thanks!

Set Block Status from xml and show if its enabled

Created CMS > Block and display it on product page as tabs following this tutorial
app/design/frontend/[theme]/default/layout/catalog.xml
<block type="catalog/product_view_attributes" name="product.sizes" as="sizes" template="catalog/product/view/sizes.phtml">
<action method="addToParentGroup"><group>detailed_info</group></action>
<action method="setTitle" translate="value"><value>Size Guide</value></action>
</block>
From the above code, block title is set from admin and it will be shown as product tab even if its disabled from admin end.
How can we show block only if its enabled from admin and check using
some IF condition in xml ?
Also is it possible to show the title given from admin end rather than setting it from XML file ?
Declare an observer of controller_action_layout_load_before event in config.xml.
<controller_action_layout_load_before>
<observers>
<namespace_module_model_observer>
<class>Namespace_Module_Model_Observer</class>
<method>setHandle</method>
</namespace_module_model_observer>
</observers>
</controller_action_layout_load_before>
Define observer.
class Namespace_Module_Model_Observer
{
public function setHandle(Varien_Event_Observer $observer)
{
if (!Mage::getModel('cms/block')->load('cms_block_identifier')->getIsActive()) {
Mage::app()->getLayout()->getUpdate()->addHandle('your_handle_name');
}
}
}
Add handle to layout xml file.
<?xml version="1.0"?>
<layout version="0.1.0">
<your_handle_name>
<reference name="product.info">
<remove name="product.sizes" />
</reference>
</your_handle_name>
</layout>

Magento: Using custom variables in a layout file

Is it possible to use Custom Variables in a layout file? I can use them in a template file like this:
Mage::getModel('core/variable')->loadByCode('variableCode')->getData('store_plain_value')
But not sure with the xml file.
I know I could use the above instead, but this would be useful to know anyway for future uses too.
UPDATE: Have been most unclear I'm afraid. I am specifically looking to access the admin panel "Custom Variables" section, not just pass my own variables to a block. I do apologise for the lack of clarity.
Mage_Core_Block_Abstract extends Varien_Object and inherits its __call() overloading. Whereas block actions in layout XML call block methods, the following are possible:
Pass a string (and it can be translated!):
<action method="setSomeVal" translate="arg" module="some/helper">
<arg>Some String</arg>
</action>
Pass an array:
<action method="setSomeVal">
<arg>
<key1>Some String</key1>
<key2>Some String</key2>
<key3>
<multikey1>Some String</multikey1>
</key3>
</arg>
</action>
Pass anything you want:
<action method="setSomeVal">
<arg helper="some/helper/method">
<param_for_the_helper_method>
<getting_crazy>Oh Boy.</getting_crazy>
</param_for_the_helper_method>
</action>
Retrieve the value in the block/template with $this->getSomeVal();.
Fun, huh?
Did you try the following :
<!-- in layout xml file -->
<action method="setData"><name>color_id</name><value>5</value></action>
Then, you can use in block file like below :
$colors = $this->getColorId();
# or
$colors = $this->getData('color_id');
Based on the updated question:
Create a helper class which wraps the core/variable functionality, e.g:
class Some_Module_Helper_Variable
{
public function getVariableData($code,$param)
{
return Mage::getModel('core/variable')->loadByCode($code)->getData($param);
}
}
Then, in layout XML for your block you can do this (I believe):
<action method="setSomeVal">
<arg helper="class_group/variable/getVariableData">
<arg1>variableCode</arg1>
<arg2>store_plain_value</arg2>
</arg>
</action>

Resources