As it turns out, it's not very difficult to decorate either the ui-bootstrap tooltip or the popover with a custom directive. This is written in typescript, but the javascript parts of it should be obvious. This single piece of code works to decorate either a tooltip or a popover:
'use strict';
module App.Directives.TooltipToggle {
    export interface DirectiveSettings {
        directiveName: string;
        directive: any[];
        directiveConfig?: any[];
    }
    export function directiveSettings(tooltipOrPopover = 'tooltip'): DirectiveSettings {
        var directiveName = tooltipOrPopover;
        // events to handle show & hide of the tooltip or popover
        var showEvent = 'show-' + directiveName;
        var hideEvent = 'hide-' + directiveName;
        // set up custom triggers
        var directiveConfig = ['$tooltipProvider', ($tooltipProvider: ng.ui.bootstrap.ITooltipProvider): void => {
            var trigger = {};
            trigger[showEvent] = hideEvent;
            $tooltipProvider.setTriggers(trigger);
        }];
        var directiveFactory = (): any[] => {
            return ['$timeout', ($timeout: ng.ITimeoutService): ng.IDirective => {
                var d: ng.IDirective = {
                    name: directiveName,
                    restrict: 'A',
                    link: (scope: ng.IScope, element: JQuery, attr: ng.IAttributes) => {
                        if (angular.isUndefined(attr[directiveName + 'Toggle'])) return;
                        // set the trigger to the custom show trigger
                        attr[directiveName + 'Trigger'] = showEvent;
                        // redraw the popover when responsive UI moves its source
                        var redrawPromise: ng.IPromise<void>;
                        $(window).on('resize', (): void => {
                            if (redrawPromise) $timeout.cancel(redrawPromise);
                            redrawPromise = $timeout((): void => {
                                if (!scope['tt_isOpen']) return;
                                element.triggerHandler(hideEvent);
                                element.triggerHandler(showEvent);
                            }, 100);
                        });
                        scope.$watch(attr[directiveName + 'Toggle'], (value: boolean): void => {
                            if (value && !scope['tt_isOpen']) {
                                // tooltip provider will call scope.$apply, so need to get out of this digest cycle first
                                $timeout((): void => {
                                    element.triggerHandler(showEvent);
                                });
                            }
                            else if (!value && scope['tt_isOpen']) {
                                $timeout((): void => {
                                    element.triggerHandler(hideEvent);
                                });
                            }
                        });
                    }
                };
                return d;
            }];
        };
        var directive = directiveFactory();
        var directiveSettings: DirectiveSettings = {
            directiveName: directiveName,
            directive: directive,
            directiveConfig: directiveConfig,
        };
        return directiveSettings;
    }
}
With this single piece of code, you can set up programmatic hide and show of either a tooltip or popover like so:
var tooltipToggle = App.Directives.TooltipToggle.directiveSettings();
var popoverToggle = App.Directives.TooltipToggle.directiveSettings('popover');
var myModule = angular.module('my-mod', ['ui.bootstrap.popover', 'ui.bootstrap.tpls'])
    .directive(tooltipToggle.directiveName, tooltipToggle.directive)
        .config(tooltipToggle.directiveConfig)
    .directive(popoverToggle.directiveName, popoverToggle.directive)
        .config(popoverToggle.directiveConfig);
Usage:
<span tooltip="This field is required."
    tooltip-toggle="formName.fieldName.$error.required"
    tooltip-animation="false" tooltip-placement="right"></span>
or
<span popover="This field is required."
    popover-toggle="formName.fieldName.$error.required"
    popover-animation="false" popover-placement="right"></span>
So we are reusing everything else that comes with the ui-bootstrap tooltip or popover, and only implementing the -toggle attribute. The decorative directive watches that attribute, and fires custom events to show or hide, which are then handled by the ui-bootstrap tooltip provider.
Update:
Since this answer seems to be helping others, here is the code written as javascript (the above typescript more or less compiles to this javascript):
'use strict';
function directiveSettings(tooltipOrPopover) {
    if (typeof tooltipOrPopover === "undefined") {
        tooltipOrPopover = 'tooltip';
    }
    var directiveName = tooltipOrPopover;
    // events to handle show & hide of the tooltip or popover
    var showEvent = 'show-' + directiveName;
    var hideEvent = 'hide-' + directiveName;
    // set up custom triggers
    var directiveConfig = ['$tooltipProvider', function ($tooltipProvider) {
        var trigger = {};
        trigger[showEvent] = hideEvent;
        $tooltipProvider.setTriggers(trigger);
    }];
    var directiveFactory = function() {
        return ['$timeout', function($timeout) {
            var d = {
                name: directiveName,
                restrict: 'A',
                link: function(scope, element, attr) {
                    if (angular.isUndefined(attr[directiveName + 'Toggle']))
                        return;
                    // set the trigger to the custom show trigger
                    attr[directiveName + 'Trigger'] = showEvent;
                    // redraw the popover when responsive UI moves its source
                    var redrawPromise;
                    $(window).on('resize', function() {
                        if (redrawPromise) $timeout.cancel(redrawPromise);
                        redrawPromise = $timeout(function() {
                            if (!scope['tt_isOpen']) return;
                            element.triggerHandler(hideEvent);
                            element.triggerHandler(showEvent);
                        }, 100);
                    });
                    scope.$watch(attr[directiveName + 'Toggle'], function(value) {
                        if (value && !scope['tt_isOpen']) {
                            // tooltip provider will call scope.$apply, so need to get out of this digest cycle first
                            $timeout(function() {
                                element.triggerHandler(showEvent);
                            });
                        }
                        else if (!value && scope['tt_isOpen']) {
                            $timeout(function() {
                                element.triggerHandler(hideEvent);
                            });
                        }
                    });
                }
            };
            return d;
        }];
    };
    var directive = directiveFactory();
    var directiveSettings = {
        directiveName: directiveName,
        directive: directive,
        directiveConfig: directiveConfig,
    };
    return directiveSettings;
}