Google Glass: Displaying a published LiveCard - google-glass

I'm having trouble displaying a LiveCard.
public class RollTheDiceActivity extends Activity {
private LiveCard mLiveCard;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_roll_the_dice);
// ^^^^^^^^^^^^^^^^^^^^^^
publishCard(this);
}
private void publishCard(Context context) {
// Already published
if (mLiveCard != null)
return;
String cardId = "my_card";
TimelineManager tm = TimelineManager.from(context);
mLiveCard = tm.getLiveCard(cardId);
RemoteViews mRemoteViews = new RemoteViews(context.getPackageName(),
R.layout.livecard_roll_the_dice);
// ^^^^^^^^^^^^^^^^^^^^^^
mLiveCard.setViews(mRemoteViews);
Intent intent = new Intent(context, RollTheDiceActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(context, 0, intent, 0));
mLiveCard.publish();
}
}
I expected to see the contents livecard_roll_the_dice instead of activity_roll_the_dice, since publishing will be instant and take over the screen.
Instead, activity_roll_the_dice content is showing. I think this means that the mLiveCard is either never published or published but not pushed to the screen.
How do I show the contents of a published card on the screen?
In case it helps, I'm launching the app through a voice trigger from home screen: "Ok Google, roll the dice"
Thank you!

Live cards are published in the background unless you pass PublishMode.REVEAL to the publish method to force it to be displayed. However, a larger problem is that live cards should be published by a background service rather than an activity. Live cards need to be owned by a long-running context in order to stay alive in the timeline while the user is navigating elsewhere in the timeline or in immersions.
So, if you want an activity to also publish a live card, you should put the live card code in a service and have the activity make a call to that service (e.g., using a binder) to publish the card.
Is there a reason you're using an activity at all and setting its content view when you expect the live card to be displayed immediately? If that's the behavior you want, you might consider removing the activity entirely and using a service instead, with the voice trigger attached to the service. The compass sample provides an example of this.

Calvin, the live card's "life" should be tied to something more "persistent", as the previous poster points out. If you look at my example code, it always uses a background service to control the life of the live card. Your activity will come and go (paused/resumed) whereas the live card is "pinned" and it's always there until you explicitly "unpublish" it.

One other thing i found that might save someone a bit of time with this problem!
When using RemoteViews for "low frequency updates" from a service to manage a LiveCard (rather than a DirectRenderingCallback for "high frequency" updates), ensure you DONT call setDirectRenderingEnabled(true) on the LiveCard.
This will cause the RemoteView to not work at all! Removing the setDirectRenderingEnabled from the liveCard when using a RemoteView to manage its view resource fixed the livecard not appearing issue for me.

Related

Return Item's Presentation Details In Rest API programatically

I have a Rest API which needs to return an item's presentation details.
I tried this line of code, but Sitecore.Context.Device is null, since this is a rest API call.
LayoutItem layoutItem = item.Visualization.GetLayout(Sitecore.Context.Device);
Update: I tried moving this code to when I index my data (hoping to read the value and write it to Solr), but I am facing the same issue.
How would I go about doing this?
The renderings are added per "device" in Sitecore, but in most cases nowadays, there's only one device. Depending on how you route your API endpoint etc., the device may not be resolved automatically. If you know you only have one device, you could pick the first device, or provide the device as a parameter. Then you can use a device switcher in case you need to call other Sitecore methods that requires a device to be set. For example like this:
var deviceName = "Default"; // The default device. Modify according to needs
var deviceItem = item.Database.Resources.Devices.GetAll().First(d => string.Equals(d.Name, deviceName, StringComparison.OrdinalIgnoreCase))
using (new DeviceSwitcher(deviceItem))
{
...
}

Can I guarantee publishing of an item I've just created?

I've got a situation where I want end-users to be able to create new Sitecore items... and then immediately be able to navigate to the Item's URL. Obviously the item will have to be published... but this happens in something of a black box. Is there a way to guarantee an item has been published from Master to Web?
Alternately, I could create the Item in the Web DB... then re-create/copy a Master version at some point. But this strategy seems fraught with peril. And maybe just a bad idea in general.
Suggestions? Am I being needlessly paranoid about creating items directly in Web?
I'll start by saying my answer is not necessarily advisable. However, depending on your situation it should work.
If the items that users are creating always have the same template you could try creating a custom item resolver that falls back to using the Master database.
Allow Sitecore to attempt to resolve the item normally.
When it fails, look in the Master database.
If the item is in there, make sure it has the correct template
Set the found item as the context item.
Using this method, you can publish the items from Master->Web s normal, but you don't have to wait until publishing is completed to see it.
Once again, this should solve the problem, but it's up to you to weigh the risks of serving up Master DB content.
You can't "guarantee" because publishing may be queued and won't go live instantly. Instead if you need instant access, I recommend a preview site that points to the master database:
How to Setup a Sitecore Preview Site to Review Content Before Publishing
You could create a event mapping to a class with the code to publish the item. In the code you can define any rule you want regarnding whether to publish or not.
<event name="item:saved">
<handler type="YourType.ItemEventHandler, YourType" method="OnItemSaved" />
</event>
And the OnItemSaved would look like this: (not tested)
protected void OnItemSaved(object sender, EventArgs args)
{
if (args == null)
{
return;
}
Item item = Event.ExtractParameter(args, 0) as Item;
var webDb = Sitecore.Configuration.Factory.GetDatabase("web");
var masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
foreach (Language language in masterDb.Languages)
{
var options = new PublishOptions(masterDb, webDb, PublishMode.SingleItem, language, DateTime.Now)
{ RootItem = item, Deep = true };
var myPublisher = new Publisher(options);
myPublisher.Publish();
}
}
And about creating the item in the web db, I also wouldn`t go that way. It would be replaced by the default publishing process unexpectedly.
Personally i don't like front-end user creating items in master database, i feel only content authors/editors should be the ones who create items from either content editor or page editor.
There is no guarantee the item gets published instantly, I would recommend you to store any user-created data in a separate database and on the redirect URL just read the data from this database.

Google Glass GDK: updating LiveCards (RemoteViews)

Having Problem updating a LiveCard using remote views. I am publishing using this code. I am assuming that you can get the LiveCard using TimelineManager.getLiveCard(id) and then publishing again. The result I get is two LiveCards. I am using the same id both times I publish the cards.
As a workaround I am unpublishing and then publishing, but that is not a smooth transition as it shows the 'Okay Glass' between.
private void publishCard(Context context) {
String cardId = "myCard";
mLiveCard = tm.getLiveCard(cardId);
mLiveCard.setNonSilent(true);
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.activity_vitals_glass);
rv = updateViews(rv, pr);
mLiveCard.setViews(rv);
Intent intent = new Intent(context, MenuActivity.class);
mLiveCard.setAction(PendingIntent.getActivity(context, 0, intent, 0));
mLiveCard.publish();
}
The updateViews() method just sets textviews on the remote view. What is the proper way to update a LiveCard with RemoteViews?
getLiveCard creates a new live card, so you should only call it once when your service is started and cache the LiveCard instance that you receive.
You can also cache the RemoteViews instance at the same time. To update the card after it's published, you'll just need to manually call setViews on the LiveCard again after you call any of the RemoteViews setters.

SKPaymentQueue addPayment doesn't always trigger native confirm dialog

Ok, I'm implementing IAP into an iOs app and only some products in the store actually trigger the native purchase handling dialogs.
Background:
The app uses cocos2dx with javascript bindings for cross-platformability. We're dipping into the iOs native sectors to implement the store handling.
These calls all work correctly:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[SKPaymentQueue canMakePayments];
[[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
A note on the last one. All product ids are checked and return as valid in the productsRequest:request didReceiveResponse:response callback but only if I don't include the bundle id in the identifiers that get sent. Most examples I saw said this was needed, but if included they all return as invalidProductIdentifiers. Could this be indicative of a problem?
So currently some products bring up the native purchase confirm dialog after their (previously verified) ids are passed to [[SKPaymentQueue defaultQueue] addPayment:payment]. Most of them simply do nothing afterwards. No callback on paymentQueue:queue updatedTransactions:transactions, no error code, no crash.
I can't see a pattern for why some work and most don't. At least one consumable, non-consumable and subscription work, so I don't think it's that. I found that if I break and step through the code pausing after [[SKPaymentQueue defaultQueue] addPayment:payment], there's a small chance a few products work more often, although it's not consistent. This lead me to think it may be a threading issue, but you can see what I've tried below and it didn't help.
Things I've tried:
Reading around SO and elsewhere, people suggested changing test users, clearing the queue with [[SKPaymentQueue defaultQueue] finishTransaction:transaction], and that Apple's Sandbox server sometimes 'has issues'. But none of this fixed it, and it strikes me as odd that I'm not getting crashes or errors, it just doesn't react at all to certain product ids.
Here's the actual call with some things I've tried:
- (void)purchaseProductWithId:(const char*)item_code
{
/** OCCASIONALLY MAY NEED TO CLEAR THE QUEUE **
NSArray *transactions = [[SKPaymentQueue defaultQueue] transactions];
for(id transaction in transactions){
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}// */
// dispatch_async(dispatch_get_main_queue(),^ {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:[NSString stringWithUTF8String:item_code]];
// [[SKPaymentQueue defaultQueue] performSelectorOnMainThread:#selector(addPayment:) withObject:payment waitUntilDone:NO];
[[SKPaymentQueue defaultQueue] addPayment:payment];
// } );
}
If there's any other code that could be useful let me know.
Thanks for your help.
Edit:
I've added the hasAddObserver check from this question and that's not the problem either.
Turns out it was a temporary thing. I'd hate to accuse Apple's sandbox servers of being flaky, but nothing was changed and then days later it suddenly worked.
So if you have a similar issue maybe take a break and come back to it later?

SharePoint List item BRIEFLY appears as edited by 'System Account' after item.update

I have a shopping cart like application running on SharePoint 2007.
I'm running a very standard update procedure on a list item:
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["Quotes"];
SPListItem item = list.GetItemById(_id);
item["Title"] = _quotename;
item["RecipientName"] = _quotename;
item["RecipientEmail"] = recipientemail;
item["IsActive"] = true;
item.Update();
site.Dispose();
}
This item updates properly, however it briefly appears as modified by System Account. If I wait a second and refresh the page, it shows up again as modified by CurrentUser.
This is an issue because on Page_Load I am retrieving the item that is marked as Active AND is listed as Modified By the CurrentUser. This means as a user updates his list, when the PostBack finishes, it shows he has no active items.
Is it the web.AllowUnsafeUpdates? This is necessary because I was getting a security error before.
What am I missing?
First off, it's not AllowUnsafeUpdates. This simply allows modifying of items from your code.
It's a bit hard to tell what's going on without understanding more of the flow of your application. I would suggest though that using Modified By to associate an item to a user may not be a great idea. This means, as you have discovered, that any modification by the system or even potentially an administrator will break that link.
I would store the current user in a custom field. That should solve your problem and would be a safer design choice.
There could be some other code running in Event Receivers and updating the item. Because event recievers runs in context of system user account, and if you update item from event reciever, the modified field will show just that: the system account has modified the item.