Important fix needed for Android app permissions

I believe there is a significant flaw in how permissions are set when you install Android apps. You get two options – Accept all or nothing. For readers not familiar with how Android app permissions work, there is a configuration file for each app that sets permissions for that app only. Permissions are needed for any functionality that affects how the app accesses things like sensors (e.g. GPS), SD Cards and the internet. These permissions do not affect any other app on the phone.

I propose an important change should be implemented at the operating system level — You should be able to accept or deny each privilege at installation time. This would make it an opt-in approach rather than an opt-out. Sure, some of you will say there are apps that can help you do that afterwards, but for tens of millions of consumers that’s not good enough. The vast majority of consumers simply don’t do take advantage of that for a variety of reasons, so having the option to accept/deny up front is the best way to go.

Yes, there is a good chance that many (most?) users would still simply accept all. However, I think increasing numbers of users would become aware that they can opt out of certain things and take advantage of the convenience and the potential for added security that this approach provides.

Developers and companies that build Android apps will probably yell loudly that this will affect how their apps work. Note that there are no technical reasons as to why this wouldn’t work. If someone checks “don’t allow internet access”, we developers can gracefully disable parts of the application and provide notifications when users attempt to access the internet. If someone disallows geolocation, then we do the same thing. Users can always opt back in if they need to. If some vendors take the approach that if you opt-out of certain things then the entire app will be disabled, then so be it. I personally would be wary of installing an app that did that.

Take the example of the screenshot below. This is the installation screen from a very popular sports app. I wonder why does it need access to my phone calls, my Accounts, or even contents of my USB storage? It doesn’t even provide an option to move the app to USB and there are no capabilities in the app (that I’m aware of) related to making phone calls. I would love to be able to opt out of these.

Android permissions

10 Essentials for developing commercial Flex 4.5.1 mobile applications

This post is for Adobe Flex/Actionscript/Flash developers who are looking to build commercial-grade mobile apps. I’ve tried to pull together a high-level check list of items you’ll need to build successful and stable apps based on Flex 4.5.1. I’ve also uploaded a fully-functional prototype that demonstrates these concepts in a real-time, GPS navigation app. You can download the app here. So, here goes.

1. Set your initial splashScreenImage and application icon. For your app to look professional you’ll want to display an image while it launches so there isn’t just a blank screen. Here’s a great blog post that goes into more detail and covers handling multiple screen resolutions. One caveat on the splashScreenMinimumDisplayTime property is use this with caution. If you delay the app start too much you run the risk of really annoying users.

<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
splashScreenImage="@Embed('assets/splashscreen.png')"
splashScreenMinimumDisplayTime="1500"
splashScreenScaleMode="letterbox">

And, be sure to set the application icon. When you install your app, this is the image that will be displayed in the phone’s UI. Configure this in the yourappname-app.xml file. Note if you image icon isn’t the absolute correct size you’ll get a compiler error:

<icon>
     <image16x16>assets/appicon16x16.png</image16x16>
     <image32x32>assets/appicon32x32.png</image32x32>
     <image36x36>assets/appicon36x36.png</image36x36>
     <image48x48>assets/appicon48x48.png</image48x48>
     <image72x72>assets/appicon72x72.png</image72x72>
     <image114x114>assets/appicon114x114.png</image114x114>
     <image128x128>assets/appicon128x128.png</image128x128>
</icon>

2. Manage your applications life-cycle. The best article to read is the old but still very useful Hero View and ViewNavigator  – Functional and Design Specification and this blog post on Understanding View and ViewNavigator. For some reason the ViewNavigatorEvent poperties listed below aren’t documented in the Adobe on-line help. I’ve complained and so should you!

  • viewActivate Event – called when the view is fully activated. It actually happens after the creationComplete event. If you want to know more about view states in general then read this Adobe article.
  • viewDeactivate Event – use this in a View if you want to handle certain things when the user changes to a different View and the current one has been deactivated.
  • removing Event – This is called right before the viewDeactivate Event. So if there is something you want to do right before the view is fully deactivated then use this event.
  • persistNavigatorState – This property works at the application level and allows you to save the navigator’s view stacks and navigation history to a local persistent object. This is a property that is set in the main application’s mxml file and by default it is set to false. The standard architecture of a mobile app is to destroy the view contents when a user switches views so that the application saves memory. But, if there is a significant cost to destroying and recreating a particular view then you should test setting this property to never. Cost in this case means the amount of time, memory and CPU it takes to destroy and recreate a view. Also, if your end user is repeating this over and over that will ultimately affect battery life. Once a view is destroyed my guess is that memory is set for garbage collection. For info see this very informative Adobe blog post.
    <s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
         xmlns:s="library://ns.adobe.com/flex/spark"
         persistNavigatorState="true">
    
  • destructionPolicy – This is a property that can be set on individual views and can prevent an individual view from having all its data destroyed when the view is deactivated. For example, you may allow some views to be destroyed where others are mission critical and shouldn’t be destroyed because it’s too expensive to recreate them. As I write this, I believe this only works if the persistNavigatorState property has been set but it’s been a while since I verified that.
    <s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
    		xmlns:s="library://ns.adobe.com/flex/spark"
    		destructionPolicy="never"
    		viewActivate="settingsViewActivateHandler(event)"
    		viewDeactivate="settingsViewDeactivateHandler(event)">
    

3. Manually changing views. Use pushView(), popView(), popToFirstview(), popAll() and replaceView().

  • pushView() navigates the user to a new screen.
  • Use popView() to move back to the previous screen.
  • popToFirstView() changes to the screen to the very first view that was opened. This is programmatically referred to as the view at the bottom of the view stack and uses the FIFO principal.
  • popAll() returns a blank screen. I’ve never used this and I haven’t come across a use case (yet) that would require given the user a blank screen.
  • replaceView() removes the current view and replaces it in the view stack with the new view you that you assign.

4. Passing data between views. One of the requirements of commercial apps is sharing data between different views. There are a number of ways to do this including singletons, dependency injection and using the data property in the pushView() method. Here are some good articles on all three:

  • Using singletons or tightly coupling data. This is typical for prototyping where you don’t want or need the overhead of a full framework. The prototype app download (link at top of page) uses a singleton model for simplicity.
  • Using framework-based, dependency injection. Use this when you want to use a framework such as Swiz, Parsely or Robotlegs.
  • Using the pushView() data property. When you have fairly simple data needs use this via the pattern pushView(viewClass:Class, data:Object = null, context:Object = null, transition:spark.transitions:ViewTransitionBase = null) Note that this pattern is for basic usage and the data object only supports standard content within the object such as Strings, Array, ArrayCollection, etc. If you have a custom class be sure to register them with the registerClassAlias() method or you’ll get runtime errors when you go to switch views.

5. Set application permissions.These are root permissions that are set via manifestAdditions for Android and infoAdditions for iOS – and these are located in the yourappname-app.xml file in your application’s root directory. Here’s an Adobe article with additional details. When the application is installed the user will be alerted to what permissions you are asking for.

<android>
     <manifestAdditions><![CDATA[
          <manifest android:installLocation="auto">
	       <!--See the Adobe AIR documentation for more information about setting Google Android permissions-->
	       <uses-permission android:name="android.permission.INTERNET"/>
	       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	       <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
	       <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
               <uses-permission android:name="android.permission.WAKE_LOCK"/>
               <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
               <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
	   </manifest>
	]]>
     </manifestAdditions>
</android>

6. Shutdown the app. This only works on Android. On iOS, the user has to do this manually.

NativeApplication.nativeApplication.exit(); 

7. Temporarily disable the screen saver. This is required in apps where you don’t want the screen to go to sleep such as navigation apps where it may be open for a long time without any user intervention. You also need to set the WAKE_LOCK permission in the manifest file.

<uses-permission android:name="android.permission.WAKE_LOCK"/>

 

//Make sure we are on a mobile device and then
//keep the application awake so it doesn't go to sleep and close the screen.                                                      
if(Capabilities.cpuArchitecture == "ARM")
{                                                                             
     NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;                                                                            
}

8. Detecting when phone rotates. If you need to know when the phone rotates use this listener:

stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGE,stateChangeHandler);

9. Gracefully fail when network connection is lost. If your app needs network access then it’s a best practice to gracefully fail and let the user know when internet connection is lost and then again when it’s restored.

public function NetworkChangeController(autoStart:Boolean = false)
{             
    var req:URLRequest = new URLRequest(_MAP_URL);
    _urlMonitor = new URLMonitor(req);
    _urlMonitor.addEventListener(StatusEvent.STATUS,serviceMonitorStatusHandler);

    NativeApplication.nativeApplication.addEventListener(Event.NETWORK_CHANGE,networkChangeHandler);
}

private function networkChangeHandler(event:Event):void
{
     if(!_urlMonitor.running)
     {
          _urlMonitor.start();
     }
}

private function serviceMonitorStatusHandler(event:StatusEvent):void
{
     trace("Network Status Event: " + event.code + ", " + _urlMonitor.available);
     _urlMonitor.stop();
     event.code == "Service.unavailable" ? _doSomething = false : _doSomething = true;
}

10. Multiple Device Support –sizing for different dpi’s. Last, but not least is using CSS and media queries to help with sizing and layout. Media queries are actually part of the W3C core CSS spec. The cool thing about them is they let you auto-majically detect the users screen dpi (dots-per-inch) and operating system and adjust your CSS accordingly. This saves a huge amount of work on your part:

@namespace s "library://ns.adobe.com/flex/spark";
/* DPI specific styles */
s|Button{
     color:#000000;
     fontWeight:bold;
}

@media (application-dpi:240)
{
     s|Button{
          color:#FF0000;
     }
}

@media (application-dpi:320)
{
     s|Button{
          color:#0000FF;
     }
}

/* Platform specific styles */
@media (os-platform:"IOS")
{
     s|Application{
          backgroundColor:#FFCCCC;
     }
     
     s|ActionBar{
          defaultButtonAppearance:beveled;
     }                      
}

@media (os-platform:"Android")
{
     s|Application{
          backgroundColor:#CCCCFF;
     }
}

URLStream, Adobe AIR and FLEX security permission issues on Windows 7

I had a particularly vexing problem that took nearly a half a day to dig to the bottom of. I was successfully able to connect to a streaming API using Adobe’s URLStream class, and I could see the passing of packets back-and-forth between the client app and the remote server using WireShark. So, there was definitely a valid connection and hand-shaking happening in the background. And, another key piece to the puzzle was the app ran just fine as a Flex app using the default bin-debug run-time settings. But, other than that running it as an AIR app or a Flex app from IIS, I simply couldn’t get any of the URLStream event listeners to acknowledge any type of connection whatsoever.

I knew this was a permissions issue, but finding documentation on AIR and Flash runtime permissions is, well, not easy. So, after quite a few searches on the internet and many dead-ends, there buried deep in some ancient scrolls of Adobe documentation were a few articles that provided the key to finally unlock the treasure chest.

You may have never heard about it before, but there is a User Flash Player Trust directory that typically contains at least one configuration file. And, in those files you can specifically grant application access to a particularly directory. In theory, there is also a Global Flash Player Trust directory. I originally thought I made the changes to that, but actually I never was able to locate it, and I ran out of time anyway. So, if someone knows where that is on Windows 7 please let me know.

Solution:

I added the pathname to the AIR executable installation directory to the air.1.0.trust.cfg file and bingo the application worked as expected.

The file typically resides in a path that looks like this: C:\Users\<username>\AppData\Roaming\Macromedia\Flash Player\#Security\FlashPlayerTrust

And, I add the following line to the file: C:\Program Files (x86)\BasicStreams.

References:

[Flash Player] Administrator Controls

[Flash Player] User Control document

Adobe Online Doc – Restricting Network APIs