Sprint & Google Voice Integration Error

I recently bought a Nexus S 4G and I’m trying to use the Sprint/Google Voice integration, but the following error keeps popping up.

We have a problem
Sorry, there was a problem determining your eligibility for a Sprint integrated account. Please try again at a later time.

It looks like this might mean several different things. Google lists these possible reasons:

  1. Users who are behind on your phone bill.  Please check with Sprint to remedy this.
  2. Users who have a corporate number oa landline number.  Currently, we don’t offer the ability to integrate corporate or landline phone numbers.
  3. You are not using a Sprint-branded mobile phone.  Nextel, PowerSource, corporate, and pre-paid phones are not compatible with Google Voice.
  4. We were in a ‘maintenance window’ during the time you tired to sign up.  Please try again in 24 hours. If you try again and are still unable to integrate your number, it is likely because of the previously mentioned reasons.
  5. If you have call blocking enabled on your account, you cannot use Google Voice on Sprint.  In order to be eligible for Google Voice on Sprint, please contact Sprint to remove this feature and then re-try. You can use Google Voice to block unknown callers and send straight to voicemail.
  6. If you have call tones enabled on your account, you cannot use Google Voice on Sprint.  We recommend contacting Sprint to remove this feature and then re-trying the integration.

None of those appeared to be my issue. My cell phone is listed on two Google Voice accounts.  So there are two GV numbers that will ring my cell phone.  Evidentially this will cause a problem on the Google end of things. I removed the cell phone number from the other Google voice account and it is letting me go through the process correctly so my Google Voice account now shows my cell phone number as the Google Voice number.

However, I still can’t login to Google Voice on my phone.  It gives me the same error. However, Google Voice seems to be working correctly and calls to my number are handled by Google Voice voicemail, transcribed and sent as a text message.

I’m curious if there is a problem with the fact that my Sprint number was set to forward to my Google voice number when it wasn’t answered.  The other issue that might be hanging things up is the fact we have a discount on the plan because of our Costco membership.

I got someone on Sprint’s chat support and they said to undo the integration and then redo it.  They also said that they reset the Google Voice settings on my account. I tried redoing it.  Google voice calls me and has me enter the verification number, but as soon as I enter it, the message on the web page changes to:

Unable to update your account. Your last change needs to be fully implemented before we can make additional changes to your account. Please try again in 15 minutes.

The tech I’m chatting with says to just wait it out. He is sure the problem will be solved when I wait. I’m asking a few questions to keep him on the chat. Now it is letting me go through the process again. Much to “Jack’s” surprise it doesn’t work.  He describes the issue as a “technical glitch” and says they have specialists who can take care of this if I call Sprint.

I’m not having much luck getting him to explain exactly what the “technical glitch” is.  However it appears that he saw something on my account that was wrong, reset it, and then when I got the error message it came back again.

Someone else is helping me and we’ve gotten the Google Voice setup again on the Google side of things, but when trying to use Google Voice on the Nexus S, it still just says:

We have a problem
Sorry, there was a problem determining your eligibility for a Sprint integrated account. Please try again at a later time.

The current technician said that the problem is that my account is listed as a Corporate or Corporation Individual type.  The only reason I can figure out why it might be listed like this is because I have a discount by being a CostCo member.  Tech support says this can be changed to an Individual Liable account without messing up anything else on the account, but for some reason tech support can’t do this.

Ok now I’m talking with another tech support person. I’m not sure why I was transfered to him since the last guy just told me tech support couldn’t help me.  This new tech wants to check everything again.  Sprint could save everyone a lot of time if they would actually add notes to the account about what they did so the next person could read them and not try the same thing over and over again.

This guy is having me turn the phone off and back on again to see if that fixes it. :(

I’m on hold and the recorded message keeps saying:

Waiting is difficult and we know your time is important.

No they don’t know that my time is important. If it was half as important to them as it is to me, I wouldn’t be stuck explaining the same thing over and over again to people and spending long periods on hold while they try to figure out who to pass me off to next.

Now I’m talking to Joe. He says the CostCo discount is the problem. Evidentially it has me listed as a CostCo employee. I asked him if he could switch my account over to whatever it needs to be to work properly without changing the current rate I’m paying.  He is checking with a supervisor and I’m on hold again with the woman’s voice who is very concerned about how important my time is.

Joe did say that the limitation is something that Google is doing–not something that Sprint is enforcing.  I’m not sure if I believe him or not, but it might be part of Google wanting to keep Google Voice from being used for business. I think their terms of service basically say not to use it for a business although a lot of people do.

Joe said my account is setup as a Corporate Liable account. I asked if that means CostCo is liable for my bill, but he said they weren’t. He can’t give me the discount unless I’m listed as a Corporate Liable–which will keep the Google Voice account from working.

Talking to Joe involves me asking a question and him pausing for 30 to 45 seconds before giving me a response that usually has nothing to do with what I asked. Maybe he is looking for a scripted response to, “how does that make any sense?”

I asked what the logic was behind classifying accounts in such a way that they won’t work with the Google Voice integration–something that they have heavily promoted and is one of the things I was very interested in having when I bought this new phone.  His response was, “well since you said you will cancel your account over this I can get you to the retention department.” I’m not sure he is even listening to anything I say. Maybe this is some type of very human sounding auto voice prompt system.

He is blaming it on Google and saying I need to call them. (That sounds more like the humans I’m used to talking to.  I pointed out that Sprint has been just bouncing me around for the past five hours and I really don’t want to have to deal with them just bouncing me to another company.  If he thinks I need to talk to Google then he should conference them in so the three of us can talk. (Not that I think this is going to happen.) He said he would see if he can make that happen.

Waiting…..

Perhaps the goal is to just keep my on hold until their phone system finally drops my call.

Still waiting about 20 minutes later.  I seriously think this is what he is doing because he isn’t allowed to just hang up on me.

Joe says he can’t get ahold of  Google, but now he is saying that this account should work.  He is transfering me to someone in technical support who has done this before.

Ok this guy can’t hear me very well… Argh.  The call dropped.

The new guy, John, called me back on my cell phone.  Now he is calling me on my land line.  Arghhh.  I can hear him, but he can’t hear me.

Ok talking to him now on my wife’s cell phone.

He is reseting something while I have the battery out of the phone.  Now he is asking me if I think the world is going to win tomorrow and telling me about a co-worker who quit their job because they thought the world was going to end.

Hm.  Maybe this guy just has false confidence.  I told him what the previous guy told me–that it wouldn’t work with my phone because to have the discount it must be a corporate type of account. He is going to check with a supervisor about that to make sure it will work. :(

Just found an Engadget post that seems to indicate the problem should be fixed now.

John suggested I change my password. Now I’m able to login to Google Voice on my phone!

Ok not so great.  When I call my cell phone number it gets answered by Sprint Voicemail not Google Voice.  I’m going to try to undo the Sprint Integration and then redo it.

I waited about an hour and tried it again and now everything seems to be working ok. I’m not exactly sure what fixed things, but I can log into Google Voice on my phone now and calls are answered by Google Voice.

Google Voice on the Nexus S, is very nice.  The only problem I’m seeing is that the voice mail notification from the old Sprint voicemail is still coming up. I can’t delete the voicemail because the account is gone.  Sprint says it should go away in 30 days if I ignore it.

If you are thinking about making the switch, I’d wait awhile…

Tapestry 5 – 10 Minute Demo of Apache Tapestry

This is a demonstration of about 10 minutes of programming in Tapestry 5 creating a sample application. The app is pretty basic and just lets you add URLs to a list and then vote on them-similar to the idea behind Digg or Reddit. I didn’t really explain things in great detail so it is more of a demonstration of some of the things you can do than it is a step by step tutorial.
Continue reading “Tapestry 5 – 10 Minute Demo of Apache Tapestry”

How to Charge for Programming

Charging for programming can be a bit tricky.  Clients obviously would prefer a solid quote. However, any experienced programmer knows that what the client wants is going to change as the software takes shape. Furthermore, any non-trivial program is going to involve some unknown problems that the programmer may be able to solve quickly, but might take a long time. It isn’t easy to estimate how long it will take to find an algorithm that does X in Y seconds.

In order to feel safe giving a firm quote, a programmer is going to have to pad the numbers quite a bit to deal with unknowns, client changes, etc.  Of course this might push the price up to the point where the client decides it isn’t worth it.

An experienced client is going to have already experienced a project where they paid lots of money just working off of an estimate only to end up with software that doesn’t work and a code base that no one else is willing to touch. They can either keep sinking money into the project or just write off the whole thing as a failure.

So how can you compromise between what the client and the programmer both need?

1. Small bites

If you can determine the smallest amount of functionality for the software to be useful to the client, do that as an independent project first.  Instead of trying to quote for an entire year long programming job, pick the part that solves the most number of issues with the least amount of work and try to have something delivered in 2 to 4 weeks or less.

The client likes this approach because you are delivering solutions to problems instead of just a program. If they can get their biggest problems solved early on with the least amount of expense, so much the better. They may want you to do x, y an z, but if x gives them 90% of the benefits, you should definitely do that as a project and then let them decide if they want to proceed with y and z.

What you learn in completing the first project will make your estimate of the next project much more accurate. The chances of you getting anywhere near an accurate estimate when estimating x, y and z all together are very low.  The chances of you being able to accurately estimate y after having completed x are much greater.

You as the programmer face a lot less risk with a 2 to 4 week project as long as the requirements are defined and the scope is clear to both parties.  Keep in mind you need to clearly articulate not only what the software will do, but also what it will not do. Make sure the client knows what is being left out and what will be part of future projects should they choose to proceed.

2. Range estimate with upper limit

The client doesn’t want to pay twice as much just because you won’t know how long the project will take until you are half way done.  If you give a single quote that factors in the risk, they may feel they are being taken advantage of.  On the other hand, you don’t want to give a low bid only to find you drastically underestimated how difficult it would be to solve particular problems, interface with their existing system, etc.

Giving an estimate such as $5,000 to $10,000 with a cap of $10,000 is often a fair way to handle the needs of both sides. The greater the unknown risks, the wider the gap between the first and second number.  Basically the second number is the amount you’d want if you were giving a hard quote.  It should factor in all the risks of dealing with unknowns, the chance that the customer will change their mind a lot, etc.  The first number should be a reasonable estimate if everything goes ok with only a few minor problems.

The client will need to commit to paying up to the higher number.  If the project is worth it to them at $5,000, but not at $10,000 then you need to reduce the scope until the value and your upper limit match.

3. Charging for programming time

Some people like charging a low rate, but charging for every minute they spend on the project. They operate with the idea that, “If I’m doing something I wouldn’t be doing on my own, the clock is running.” This seems reasonable from the programmer’s standpoint.  However, imagine you are personally hiring a graphic designer to create some designs in HTML 5. The designer is good, but has mainly done work in HTML 4.  As a result they are going to be spending at least some of their time learning exactly how to use HTML 5. Do you want to be paying for their learning curve? Probably not.

Chances are very high that not all of your time on a programming project are going to be spent actually coding.  You’ll probably spend time doing the following:

  • Reading the documentation for your framework
  • Looking for open source libraries that will do what you need
  • Looking through mailing lists archives to see how other people solved similar problems.
  • etc.

These all might sound like reasonable things to charge for, but they are investments in making you a better programmer. My preference is to charge a much higher rate as an expert, but not bill for learning anything new.

I use a time tracking tool (Mylyn and TaskTop) that measures how long I spend working on a particular issue in my IDE.  That way I’m only measuring the time spend coding and not any of the time I spend doing research. The tool I use, times out after three minutes.  So if I just need to jump over to lookup the specifics of an API call, all the time is counted.  However, if I head off on a 30 minute search for a better open source expression language to embed in my program, it isn’t.

There are three consequences of this type of billing:

  • The hourly rate I charge is much higher than some of my peers.
  • 20 to 30 billable programming hours is a full week.
  • My estimates are much more accurate because I’m only estimating actual coding time.

4. Getting paid

With known and trusted clients, I bill at the end of the month for any work performed during that month.  With unknown clients, I prefer that they pay ahead of time.  When my work depletes their deposit, they need to deposit some more money.

5. Partnerships

The world is full of people with no programming skills who are trying to invent the next Facebook and feel that the only thing holding them back is the fact that they can’t afford a programmer willing to work for a percentage of the company. You want to avoid people like that.  Ideas are cheap and generally you don’t want to ever partner with someone who is wanting you to bring the man hours and they will bring the “ideas”.

However, there are people that have something significant to offer that you can’t get easily on your own.  In particular this comes in the form of marketing and existing customers. The hard part of making money from selling software isn’t writing the software–it is getting noticed.  Partnerships with people who can help your product get noticed can be valuable.

You want to avoid partnerships where you front all the risk though. Your partner needs to have some type of incentive to use their connections, mailing list, clout or whatever to promote the product once it is ready to go.  One easy way to do this is to split the development cost.  You approach things the same way you do with a client, but you and your partner are both responsible for half the bill.  If you are operating as a sole proprietor, then you simply don’t pay your half of the bill.  If you have a corporation you may pay your half personally.

This type of arrangement means you both have something invested.  You have your time and they have their money–albiet a lot less money than they would have if they were to have tried to do it on their own.

If you deliver the software, but your partner turns out to be incapable of actually marketing it, you still have half of what you’d normally bill.

Partnerships are tricky and you need to be very clear and very careful how you set things up, so make sure you do your homework.  The main point here is to not overlook partnerships when the partner has something genuine to offer–and very rarely is that going to be their idea.

Tapestry Facebook Share Component

I am working on a project where we need to be able to do a Facebook share on a particular page for an event from multiple places within a web application. Putting this functionality into a Tapestry component makes it easy to call it from where ever it is needed and the code makes for a nice concise example of how components work in Tapestry.

In Tapestry components consist of two parts. The first part is the .tml file and the second is the .java file. In general the .tml file is concerned with how things render out in HTML and the .java file is concerned with the programatic side of things and retrieving the data.

The end result is going to be a tag that we can use in other .tml files that will look like this:

<t:facebookshare event="myEvent"/>

First lets look at the .tml file. This file is saved under:
/src/main/resources/com/example/myapp/components/FacebookShare.tml

<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" >
<a href="#" onclick="window.open('http://www.facebook.com/sharer.php?u=${facebookShareURL}&amp;display=popup','fbshare','menubar=0,location=0,resizable=1,width=700,height=350')">
	Please share this event on Facebook
</a><br/>
</t:container>

The ${facebookShareURL} is what will call getFacebookShareUrl() on the java class in order to fill out the component with the data it needs. In this case it will be an encoded URL.

The .java component file is saved in:
/src/main/java/com/example/myapp/components/FacebookShare.java

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.persistence.Transient;

import net.xeric.register.entities.Event;

import org.apache.tapestry5.Link;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.PageRenderLinkSource;

public abstract class FacebookCommon {
    
    @Inject
    private PageRenderLinkSource linkSource;
    
    @Parameter(required=true)
    @Property
    private Event event;
    
    public String getFacebookShareURL() {
        Link link = linkSource.createPageRenderLinkWithContext("EventInfo", event);
        String linkURL = "";
        try {
            linkURL =  URLEncoder.encode(link.toAbsoluteURI(),"UTF-8");
        } catch (UnsupportedEncodingException e) {          
            e.printStackTrace();
        }
        return linkURL;
    }
}

I have a page called EventInfo that shows all the information about a particular event. So this component takes an event as a parameter and then constructs the link to share on the EventInfo page.

This is how we tell Tapestry that we have a required parameter that needs to be bound to an event:

    @Parameter(required=true)
    @Property
    private Event event;

That means that when we use the component like this:

<t:facebookshare event="myEvent"/>

Tapestry is going to expect the parameter event to be bound to an event object.

Line 42 has the code that constructs our link back to the EventInfo page using the context of the event that we’ve passed in as a parameter to the component.

        Link link = linkSource.createPageRenderLinkWithContext("EventInfo", event);
        String linkURL = "";
        try {
            linkURL =  URLEncoder.encode(link.toAbsoluteURI(),"UTF-8");

The rest of the getFacebookShareURL method simply encodes the URL as a string and returns it. This is the value that replaces the ${facebookShareUrl} in the template when the component is rendered.

Get the URL of a Page in Tapestry 5

Sometimes your program will need to get the full URL of a page to send in an email, share on Facebook or run through a URL shortener to send to Twitter. You can do this by injecting the HTTPRequest and the building a string representation of the URL manually, but this is a lot more work that it needs to be. Here is a simple way to do it using Tapestry’s PageRenderLinkSource and a Link object.

@Inject
PageRenderLinkSource linkSource

/**
 * Return a string with the full URL of MyPage with a 
 * context of 5.
 */
public String getPageURL() {
	Link link = linkSource.createPageRenderLinkWithContext("MyPage", 5);
	return link.toAbsoluteURI();
}

I’ve hard coded the value 5 as the context–you’d normally set that based on whatever you are wanting to share. This method will return a link to MyPage with a context of 5, so it will probably look something like: http://www.myserver.com/MyPage/5. One of the nice things about this solution is that it will automatically handle things if your application needs to use a URL like: http://www.myserver.com/myapp/MyPage/5