Getting Cortana if it is not visible or blocked for your region on Windows Phone 8.1

wp_ss_20141220_0008You can still get Cortana, even if your carrier has block/not rolled it out, provided you can do the manual updates.

Worth noting that some carriers will intentionally block the update for a while with phones already out there based on your regional settings, this is so they can sell the new ones with it enabled as a selling point. Hence the 630 got it before you could update the 920… but as I mention you can still get it, provided you can upgrade your phone to 8.1 and relatively recent updates, newer the updates the newer the version you will get and the more “languages and accents will be supported”.

Also worth knowing – you might already have it if you are the latest update, it might be that it is just not switched on, default is “off”… On most older phones, including 920, it is still classed as a “Beta” application which replaces the existing speech support built into those devices since 8.0…

Finding it if you already have it: –

wp_ss_20141220_0001wp_ss_20141220_0002open “Settings”

  • you will be on the default tab “system”, swipe to the side so you are on “applications”, if it is available with your current configuration, it will be listed. 
  • Click “Cortana”.
  • Turn it on.
  • Restart the phone if required.
  • Hold down search button to start it.

If blocked or not visible – getting it if you do not have it: –

This varies somewhat depending on your device and update availability… easiest thing to do is change everything to “English (United States)” turn on Cortana and then try adjusting things back to your region one by one… when Cortana stops working change whatever you last changed back to “English (United States)”

The three areas to change are “Region”, “Language” and “Speech”. Then you need to turn it on.

Cortana will only work if “Language” and “Speech” match and Cortana is available for that combination.

System Settings   System Settings

Here I have it working with both English UK and US note that “Language” matches “Speech”

open “Settings” 

  1. Region SettingsUnder the default tab “system” scroll down and go into “Region”.
  2. Change “country/region” to “United States” (if Cortana not available to you).
  3. Change “Regional format” to <your desired format> (for me “English (United Kingdom)”).  
    • This preserves your currency and date format.
  4. Click on “Restart Phone”.
  5. Check for any updates, and install them, restart as required.
    • This will get Cortana and other updates if not already installed.
       
  6. Language SettingsUnder the default tab “system” scroll down and go into “Language”.
  7. Change the language to match the region setting (“English (United States)”).
  8. Click on “Restart Phone”.
  9. Next bit differs depending on whether Cortana is available in your local language version… including the variations in English accent and pronunciation.
    • If it is, available in your language/accent.
      1. from within “Settings”.
      2. System Applicationsif on “system” tab, swipe to the side so you are on “applications”
      3. if available you will see Cortana at or near the top.
    • If it is not visible within “applications” tab (within “Settings”)
      1. Go back to the “system” tab.
      2. Scroll down to to “speech”.
      3. Go into “speech” and change the “Speech language” to “English (United States)” … or another one that is currently supported by cortana…

        System SettingsSystem SettingsNote: Depending on your current phone setup, you may need to download, then go back into this and reselect it to get it to install, follow the prompts, reboot as required and then check for any phone updates, which will get the updated speech package which includes cortana.

      4. Make sure “speech” matches “language”.
      5. System Application SettingsCortana SettingsOnce done with all the updates/install of language packs, as above, go into settings, swipe to side to get “applications” tab… and you will see Cortana listed… open it and switch it on.
      6. Restart phone if required, hold down search button an say hello to Cortana.

Finding the columns and values from AggregateResult (or QueryResult/sObject) in Salesforce.com APEX

I have been doing some quite intensive Saleforce.com (Visualforce.com) custom site development recently. This has involved full front to back-end development on multiple levels along with integration into various jQuery and charting frameworks.

One issue I ran into I could find no immediate recommended solutions in the various forums. This was having the ability to iterate through a result set, determine the column names and values.

While retrieving the data was relatively simple through SOQL, after employing the various workarounds for the lack of ability to do simple joins. Once I had my query I needed to consume it dynamically from multiple sources (different AggregateResult sets).

In order to make the application robust the consumption of the AggregateResult set needed to be dynamic, and be able to adapt to varying data that might be supplied to it i.e. for the chart output we would have some standard fields, but there would be additional fields the number of which would vary depending on the result set.

In most development languages there is some object model to verify that a column exists and if it does get your value out of it. AggregateResult is the same if you are using C#, the result set is XML so you can confirm structure, but within APEX there is currently no ability to do that.

At first I though I could use “<my agg res>.getSObjectType().getDescribe().fields.getMap()”, but I soon found that only returned one field, an internal ID field, unrelated to my data.

After searching for a quick solution, nothing obvious could be found, so had to figures something else out.

I did try to serialize the result set but that failed as well. Apparently sObjects cannot be serialized (within APEX), which I found odd.

While trying to debug and figure out a solution, I stumbled onto the fact that the AggregateResult object would convert to a string… that led me to the solution.

The string (at least for now) follows a predictable format:

string somethingToWorkWith = string.valueOf(myAggregateResult);

Will give me a string which has the format:

AggregateResult:{MyColumn1=Value1, MyColumn2=Value2}

This allows me to pull out all of my data, with their types intact. Below are a couple of functions, one will get me all my columns in a set, the other will get me all my columns and values in a key/value map. Note that in order to preserve the original type (class) of data the later function’s value is a generic object, and it is pulled from the original AggregateResult, rather than from the converted string array.

/**
* Returns set of columns in the supplied AggregateResult.
**/
public static Set<string> AggResColumns(AggregateResult a) {
    if (a == null) return new Set<string>();
        set<string> myColumns = new set<string>();
        string ar = string.valueOf(a).removeStart(‘AggregateResult:’).removeStart(‘{‘).removeEnd(‘}’);
        string[] ars = ar.split(‘, ‘, 0);
        for (string pair :ars) {
            if (pair != null && pair != && pair.indexOf(‘=’) > 0) {
            string[] keyAndValue = pair.split(‘=’, -2); //We are using -2 deliberately.
           if (keyAndValue.size() > 0 && keyAndValue[0] != null && keyAndValue[0] != ) {
                myColumns.add(keyAndValue[0]);
            }
        }
    }

    return myColumns;
}

/**
* Returns map of columns and values in the supplied AggregateResult.
**/
public static map<string, object> AggResColumnsAndValues(AggregateResult a) {
map<string, object> myValues = new map<string, object>();
string ar = string.valueOf(a).removeStart(‘AggregateResult:’).removeStart(‘{‘).removeEnd(‘}’);
   
string[] ars = ar.split(‘, ‘, 0);
   
for (string pair :ars) {
       
if (pair != null && pair != && pair.indexOf(‘=’) > 0) {
           
string[] keyAndValue = pair.split(‘=’, -2); //We are using -2 deliberately.
           
if (keyAndValue.size() > 0 && keyAndValue[0] != null && keyAndValue[0] != ) {
               
myValues.put(keyAndValue[0], a.get(keyAndValue[0]));
           
}
        }
    }

    return myValues;
}